在 Autofac 中,最内部的范围始终是容器。使用 AutofacDependencyResolver,它会是
AutofacDependencyResolver.Current.ApplicationContainer
没有办法从嵌套范围(如果你只有一个ILifetimeScope)“向后走”到容器。无论如何,我不一定确定你想这样做。
听起来您的 SingleInstance 组件正在执行某种服务定位,基本上是手动注册/解析某些组件。如果要注册的类型集是固定的,我可能会建议(如果可能)重新设计您的系统,因此 SingleInstance 组件不再注册为 SingleInstance 而是注册为 InstancePerDependency,然后将这些其他项目作为构造函数参数。
而不是...
// Consuming class like this...
public class BigComponent
{
public void DoSomethingCool()
{
using(var scope = ...)
{
var c = scope.Resolve<SubComponent>();
c.DoWork();
}
}
}
// ...and container registrations like this...
builder.RegisterType<BigComponent>().SingleInstance();
你可以试着颠倒一下:
// Consuming class like this...
public class BigComponent
{
private SubComponent _c;
public BigComponent(SubComponent c)
{
_c = c;
}
public void DoSomethingCool()
{
_c.DoWork();
}
}
// ...and container registrations like this...
builder.RegisterType<BigComponent>().InstancePerDependency();
builder.RegisterType<SubComponent>().InstancePerLifetimeScope();
这个想法是不必做即时注册和立即解决的事情。
如果您在执行服务定位时遇到困难,如果您需要绝对最内层范围,则需要使用 AutofacDependencyResolver.Current.ApplicationContainer,但请记住,如果您这样做,您注册范围为 InstancePerHttpRequest 的任何对象都将无法解析,所以你可能会遇到麻烦。确实建议改用AutofacDependencyResolver.Current.RequestLifetimeScope。这将使您的方法:
var requestScope = AutofacDependencyResolver.Current.RequestLifetimeScope;
using (var scope = requestScope.BeginLifetimeScope(cb => {
cb.RegisterType<X>().InstancePerLifetimeScope();
// ...
}))
{
var comp = scope.Resolve<X>();
// ...
}
在测试环境中,AutofacDependencyResolver 允许您交换提供程序,该提供程序指示如何生成请求生命周期。您可以像这样实现一个简单/存根:
public class TestLifetimeScopeProvider : ILifetimeScopeProvider
{
readonly ILifetimeScope _container;
private ILifetimeScope _lifetimeScope = null;
public TestLifetimeScopeProvider(ILifetimeScope container)
{
if (container == null) throw new ArgumentNullException("container");
_container = container;
}
public ILifetimeScope ApplicationContainer
{
get { return _container; }
}
public ILifetimeScope GetLifetimeScope()
{
if (_lifetimeScope == null)
{
_lifetimeScope = ApplicationContainer.BeginLifetimeScope("httpRequest")
}
return _lifetimeScope;
}
public void EndLifetimeScope()
{
if (_lifetimeScope != null)
_lifetimeScope.Dispose();
}
}
再说一遍,这只是一个用于单元测试的存根,而不是您在生产中使用过的东西。
然后,当您在测试中连接 DependencyResolver 时,您将提供您的生命周期范围提供程序:
var lsProvider = new TestLifetimeScopeProvider(container);
var resolver = new AutofacDependencyResolver(container, lsProvider);
DependencyResolver.SetResolver(resolver);
这使您可以在没有实际请求上下文的情况下使用InstancePerHttpRequest 和此类内部单元测试。这也意味着您应该能够在注册/解析方法中使用请求生命周期范围,而不必依赖应用程序容器。