如何从自定义属性解析 Autofac 按请求服务

How to resolve Autofac per-request service from custom attribute

我已经像这样配置了我的 EF 上下文

        b.RegisterAssemblyTypes(webAssembly, coreAssembly)
            .Where(t => t.IsAssignableTo<DbContext>())
            .InstancePerLifetimeScope();

我想从使用我的 EF 上下文访问数据库的自定义授权属性中使用它。这意味着没有构造函数注入。我通过使用 CommonSeviceLocator

实现了这一点
        var csl = new AutofacServiceLocator(container);
        ServiceLocator.SetLocatorProvider(() => csl);

...

        var user = await ServiceLocator.Current
           .GetInstance<SiteContext>().FindAsync(id);

我发现如果浏览器同时发出两个使用此属性的路由请求,则会失败并出现 "multiple connections not supported" 错误。看起来这可能是 due to what is mentioned in this answer。我的猜测是 ServiceLocator 从根范围而不是 Web 请求范围解析,并且这两个请求是冲突的(单独的请求都可以正常工作)。

当我更改为 InstancePerRequest() 时,我从对该属性的任何调用中得到它。

似乎证实了这一点
 Autofac.Core.DependencyResolutionException No scope with a Tag matching 'AutofacWebRequest' is visible from the scope in which the instance was requested. This generally indicates that a component registered as per-HTTP request is
 being requested by a SingleInstance() component (or a similar scenario.) Under the web integration always request dependencies from the DependencyResolver.Current or ILifetimeScopeProvider.RequestLifetime, never from the container  itself.

所以看来 ServiceLocator 根本不是可行的方法。

如何从属性内部解析请求范围的 SiteContext(使用服务定位器模式)?

您的问题源于您试图将 behavior 放入属性中这一事实。属性用于在代码元素和程序集上定义 元数据 ,而不是用于行为。

Microsoft 对 Action Filter Attributes 的营销导致人们将 DI 和 Attribute 放在同一个 class 中,从而误入歧途。如post中所述passive attributes, the solution is to break apart filter attributes转成2classes:

  1. 不包含使用元数据标记代码元素的行为的属性。
  2. 一个全局注册的过滤器,用于扫描属性并在存在时执行所需的行为。

有关更多示例,请参见以下内容:

  • Implementing passive attributes with dependencies that should be resolved by a DI container

  • Dependency Injection in Attributes: don’t do it!

  • Injecting dependencies into ASP.NET MVC 3 action filters. What's wrong with this approach?

  • How can I test for the presence of an Action Filter with constructor arguments?

另一种选择是使用 IFilterProvider 来解析 IFilterProvider and separation of concerns 中的过滤器。

一旦您了解属性本身不应该做任何事情这一事实,将它们与 DI 一起使用就相当简单了。