【问题标题】:How to resolve Autofac per-request service from custom attribute如何从自定义属性解析 Autofac per-request 服务
【发布时间】:2018-01-30 22:37:19
【问题描述】:

我已经像这样配置了我的 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);

我发现如果浏览器使用此属性同时向路由发出两个请求,则会失败并显示“不支持多个连接”错误。看起来这可能是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(使用服务定位器模式)?

【问题讨论】:

  • Standard Web API Filters are Singletons。你可以在这里查看。
  • @ErkanDemirel 是的,但它不像 ServiceLocator 缓存响应,它在每次调用时都会获得一个新响应!我的猜测是过滤器代码在 Autofac 创建其请求范围之前运行。
  • 它会在每个请求中获得一个新的,但它会在该请求中与控制器共享这个。 (我已经测试过了)。
  • @ErkanDemirel 这正是我想要的,但这不是正在发生的事情。大多数组件都会这样做,但是该属性似乎使用单例。

标签: entity-framework dependency-injection inversion-of-control autofac


【解决方案1】:

您的问题源于您试图将 behavior 放入属性中。属性用于在代码元素和程序集上定义 meta-data,而不是用于行为。

Microsoft 对 Action Filter Attributes 的营销导致人们通过将 Filter 和 Attribute 放在同一个类中而走上了错误的道路。如帖子passive attributes 中所述,解决方案是将filter attributes 拆分为2 个类:

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

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

另一种选择是使用IFilterProvider 来解析过滤器,如IFilterProvider and separation of concerns

一旦你明白了属性不应该自己做任何事情的事实,将它们与 DI 一起使用就相当简单了。

【讨论】:

  • 好的,我明白你在说什么......但在第一个例子中至少不会有同样的问题吗?过滤器在全局范围内解析 - 而不是在 AutofacWebRequest 范围内 - 因此将是一个单例。如果属性本身只有一个实例,那么所有生命周期仍然与服务定位器模式相同,不是吗?
  • 正如 Erkan 在 cmets 中指出的,有两种方法可以解决这个问题 1) 使用 Autofac 接口而不是 WebAPI 接口 2) 使用依赖范围中的服务定位器(通过语境)。见the examples。有一个可能的第三个选项对 DI 更友好 - 注入 abstract factory 以在操作过滤器中创建您的 SiteContext 实例,而不是使用服务定位器。
  • 啊,我想 2) 是我想要的。显然 DI 友好的东西更好,所以我可能会先尝试,但对于像这样的一些孤立的基础设施......嗯......
  • 这很有效,尽管获得属性的存在本身就是一个有趣的难题。对于 webapi 过滤器,它是: Enumerable.Any(actionContext.ActionDescriptor.GetCustomAttributes());
猜你喜欢
  • 1970-01-01
  • 2019-11-21
  • 1970-01-01
  • 1970-01-01
  • 2022-01-08
  • 1970-01-01
  • 1970-01-01
  • 2023-03-04
  • 2021-11-13
相关资源
最近更新 更多