如何从自定义属性解析 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:
- 不包含使用元数据标记代码元素的行为的属性。
- 一个全局注册的过滤器,用于扫描属性并在存在时执行所需的行为。
有关更多示例,请参见以下内容:
Implementing passive attributes with dependencies that should be resolved by a DI container
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 一起使用就相当简单了。
我已经像这样配置了我的 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:
- 不包含使用元数据标记代码元素的行为的属性。
- 一个全局注册的过滤器,用于扫描属性并在存在时执行所需的行为。
有关更多示例,请参见以下内容:
Implementing passive attributes with dependencies that should be resolved by a DI container
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 一起使用就相当简单了。