Autofac + WebApi。 InstancePerLifetimeScope 依赖的双重实例化
Autofac + WebApi. Double instantiation of InstancePerLifetimeScope dependency
我发现 WebApi 集成存在问题。
示例项目:https://github.com/VKrol/WebApplication19
尝试创建对“~/api/values”的请求,class Foo 已被实例化两次,尽管 class Foo 已被注册为 InstancePerLifetimeScope。请注意,我在 Application_AcquireRequestState 中解析了第一个实例,第二个实例已注入到 ValuesController 构造函数中。
我认为这是一个错误。
谢谢。
我认为这不是 Autofac
中的错误。
LifeTimeScopes are dependant on the scope in which they were resolved。在你的情况下,我认为你在两个不同的范围内解析 Foo
。在应用程序根范围 (Application_AcquireRequestState
) 及其子范围 (ValuesController
) 中。 Autofac
不允许从子范围解析,因此您的服务请求都是独立解析的。
在 AcquireRequestState
中注释掉决议后,我向您的项目添加了另一个 class NClass
,它要求 Foo
,我看到 Foo
按预期只解决一次。
public class ValuesController : ApiController {
private readonly Foo _foo;
private NClass _nclass;
public ValuesController(Foo foo,NClass nClass) {
_foo = foo;
_nclass = nClass;
}
public IEnumerable<string> Get() {
return new[] { _foo.Id.ToString(), _nclass.Id.ToString()};
}
}
public class NClass
{
private Foo _foo;
public NClass(Foo foo) { _foo = foo; }
public int Id { get { return _foo.Id; } set { } }
}
简短版本是:您在 Web API 项目中,但您正在尝试使用 MVC 依赖项解析器。您尚未设置演示项目中任意位置的 MVC 依赖解析器。
当您的事件处理程序调用 DependencyResolver.Current.GetService<Foo>();
时,它将使用默认的 MVC 依赖解析器,不是 Autofac。
public class WebApiApplication : HttpApplication {
protected void Application_Start() {
GlobalConfiguration.Configure(WebApiConfig.Register);
var builder = new ContainerBuilder();
var config = GlobalConfiguration.Configuration;
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
builder.RegisterType<Foo>().AsSelf().InstancePerLifetimeScope();
var container = builder.Build();
// Here's where the Web API resolver is set up...
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
}
protected virtual void Application_AcquireRequestState(object sender, EventArgs e) {
// ...but this call is using the MVC dependency resolver!
var foo = DependencyResolver.Current.GetService<Foo>();
}
}
如果您查看 System.Web.Mvc.DependencyResolver.DefaultDependencyResolver
的作用,它会在请求的类型上调用 Activator.CreateInstance(type)
。在这种情况下,您的 Foo
类型。
所以 - 你会得到两个不同的实例,因为你的依赖解析器没有正确设置。
如果你想使用 MVC 依赖解析器,你可以通过设置它来自由地做到这一点 per the documentation. Note that this will share the container, but not the request lifetime scope mechanism. If a Web API request comes in, it does not necessarily create a request lifetime scope in the same way as MVC so per-request dependencies will not work the way you think. There is a different mechanism to handle request lifetimes in Web API and that's also in the docs。
如果您使用的是非 OWIN Web API 东西,您可以调用 GlobalConfiguration.Configuration.DependencyResolver
来获取 Web API 依赖解析器,您已经使用 Autofac 设置了它。但是,您无法从中获取每个请求的范围,也无法解决每个请求的依赖关系。但是,如果您必须手动解析服务,那就是您的做法。
如果您选择切换到 OWIN Web API,则没有全局配置或全局依赖项解析器。然后你将被迫使用附加到请求消息的 DependencyScope
或使用像 CommonServiceLocator
.
这样的机制
我发现 WebApi 集成存在问题。
示例项目:https://github.com/VKrol/WebApplication19
尝试创建对“~/api/values”的请求,class Foo 已被实例化两次,尽管 class Foo 已被注册为 InstancePerLifetimeScope。请注意,我在 Application_AcquireRequestState 中解析了第一个实例,第二个实例已注入到 ValuesController 构造函数中。 我认为这是一个错误。
谢谢。
我认为这不是 Autofac
中的错误。
LifeTimeScopes are dependant on the scope in which they were resolved。在你的情况下,我认为你在两个不同的范围内解析 Foo
。在应用程序根范围 (Application_AcquireRequestState
) 及其子范围 (ValuesController
) 中。 Autofac
不允许从子范围解析,因此您的服务请求都是独立解析的。
在 AcquireRequestState
中注释掉决议后,我向您的项目添加了另一个 class NClass
,它要求 Foo
,我看到 Foo
按预期只解决一次。
public class ValuesController : ApiController {
private readonly Foo _foo;
private NClass _nclass;
public ValuesController(Foo foo,NClass nClass) {
_foo = foo;
_nclass = nClass;
}
public IEnumerable<string> Get() {
return new[] { _foo.Id.ToString(), _nclass.Id.ToString()};
}
}
public class NClass
{
private Foo _foo;
public NClass(Foo foo) { _foo = foo; }
public int Id { get { return _foo.Id; } set { } }
}
简短版本是:您在 Web API 项目中,但您正在尝试使用 MVC 依赖项解析器。您尚未设置演示项目中任意位置的 MVC 依赖解析器。
当您的事件处理程序调用 DependencyResolver.Current.GetService<Foo>();
时,它将使用默认的 MVC 依赖解析器,不是 Autofac。
public class WebApiApplication : HttpApplication {
protected void Application_Start() {
GlobalConfiguration.Configure(WebApiConfig.Register);
var builder = new ContainerBuilder();
var config = GlobalConfiguration.Configuration;
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
builder.RegisterType<Foo>().AsSelf().InstancePerLifetimeScope();
var container = builder.Build();
// Here's where the Web API resolver is set up...
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
}
protected virtual void Application_AcquireRequestState(object sender, EventArgs e) {
// ...but this call is using the MVC dependency resolver!
var foo = DependencyResolver.Current.GetService<Foo>();
}
}
如果您查看 System.Web.Mvc.DependencyResolver.DefaultDependencyResolver
的作用,它会在请求的类型上调用 Activator.CreateInstance(type)
。在这种情况下,您的 Foo
类型。
所以 - 你会得到两个不同的实例,因为你的依赖解析器没有正确设置。
如果你想使用 MVC 依赖解析器,你可以通过设置它来自由地做到这一点 per the documentation. Note that this will share the container, but not the request lifetime scope mechanism. If a Web API request comes in, it does not necessarily create a request lifetime scope in the same way as MVC so per-request dependencies will not work the way you think. There is a different mechanism to handle request lifetimes in Web API and that's also in the docs。
如果您使用的是非 OWIN Web API 东西,您可以调用 GlobalConfiguration.Configuration.DependencyResolver
来获取 Web API 依赖解析器,您已经使用 Autofac 设置了它。但是,您无法从中获取每个请求的范围,也无法解决每个请求的依赖关系。但是,如果您必须手动解析服务,那就是您的做法。
如果您选择切换到 OWIN Web API,则没有全局配置或全局依赖项解析器。然后你将被迫使用附加到请求消息的 DependencyScope
或使用像 CommonServiceLocator
.