我有一个使用Autofac进行依赖注入的ASP.NET MVC Web应用程序。有时,此Web应用程序将启动一个线程,以便与请求线程分开执行某些工作。当后台线程启动时,它会从根容器建立一个新的Autofac生存期范围并运行一些操作。
public IAsyncResult Run<T>(Action<T> action)
{
var NewTask = System.Threading.Tasks.Task.Factory.StartNew(() =>
{
using (var Scope = Runtime.Container.BeginLifetimeScope())
{
var Input = Scope.Resolve<T>();
action(Input);
}
});
return NewTask;
}
我在Autofac中注册的一个依赖项有两个不同的实现:一个适用于http请求生存期,另一个适用于所有其他生命周期。我试着将它们注册如下:
builder
.Register(c => new Foo())
.As<IFoo>()
.InstancePerLifetimeScope();
builder
.Register(c => new FooForHttp(HttpContext.Current))
.As<IFoo>()
.InstancePerMatchingLifetimeScope(WebLifetime.Request);
Autofac为http请求选择FooForHttp
(按预期方式)。但是,当我的后台线程旋转时,任何解决IFoo
的尝试都会导致异常:
范围内不会显示带有匹配'httpRequest'的标记的范围 在其中请求实例。这通常表明a 按HTTP请求注册的组件正在被a重新请求 SingleInstance()组件(或类似场景。)在Web下 集成始终请求来自的依赖项 DependencyResolver.Current或ILifetimeScopeProvider.RequestLifetime, 从来没有从容器本身。
我知道Autofac始终使用最后注册的提供程序作为特定组件的默认提供程序。我在这里假设它将使用最后注册的合适的提供程序。
我是否遗漏了某些内容,或者是否有更好的方法根据当前生命周期范围的标记选择提供商?
答案 0 :(得分:7)
正常注册网络Foo,但不注册其他Foo。在为异步任务创建生命周期范围时,请使用在ContainerBuilder上执行操作的BeginLifetimeScope()重载。在此操作中注册背景Foo(b =&gt; b.Register()),这应该覆盖网络。 (小键盘对不起:))
答案 1 :(得分:0)
这也可以通过使用标记的生命周期范围来解决。 注册您的fisrt Foo作为标记范围的实例:
builder.RegisterType<Foo>().As<IFoo>.InstancePerMatchingLifetimeScope("YourScopeTag");
使用您注册依赖项的相同标记创建范围:
using (var Scope = Runtime.Container.BeginLifetimeScope("YourScopeTag"))
{
var Input = Scope.Resolve<T>();
action(Input);
}
没有测试过,但应该可以正常使用
http://docs.autofac.org/en/latest/lifetime/instance-scope.html#instance-per-matching-lifetime-scope