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.

这样的机制