具有单个容器的Autofac多个使用寿命范围

时间:2019-04-15 07:40:13

标签: c# asp.net dependency-injection inversion-of-control autofac

我正在尝试解决在单个Container中使用多个生命周期的问题。

问题与InstancePerRequest()的实施有关。

有一个基于WebAPI且带有自定义WebHandler的应用程序,因此Autofac无法定义LifetimeScope是初始化还是处置。所以我不能使用基本的InstancePerRequest()。我决定根据Autofac documentation

实施半定制InstancePerRequest()

Autofac注册如下:

...
private static IContainer Container;

private static void RegisterServices()
{
    var builder = new ContainerBuilder();
    builder.Register((c, p) => new CustomClass(p.Named<List<int>>("codes"), p.Named<User>("user")))
            .InstancePerRequest();

    Container = builder.Build();
}

public static ILifetimeScope BeginLifetimeScope()
{  
    return Container.BeginLifetimeScope(new[] { MatchingScopeLifetimeTags.RequestLifetimeScopeTag });
}
...
根据{{​​3}}(第2点), MatchingScopeLifetimeTags.RequestLifetimeScopeTag是Autofac Custom每个请求语义中必需的

所以我手动创建了LifetimeScope

... // AutofacHelper.BeginLifetimeScope() is implemented above
using (var lifetimeScope = AutofacHelper.BeginLifetimeScope())
{
    result = InvokeRequest(request.Api, context);
} 
...

问题是LifetimeScope的数量与请求的数量一样多。我需要的范围从远离代码的地方开始,在那儿我需要访问它。我需要可以从任何地方访问当前范围。

我想我必须用LifetimeScope标记每个HttpContext.Current,这将足以定义我需要使用的范围。

但是我该怎么做?使用参数BeginLifetimeScope()实现new[] { MatchingScopeLifetimeTags.RequestLifetimeScopeTag, HttpContext.Current }会导致异常,因为找不到所需的作用域。

是否可以定义当前请求中使用的范围?例如使用我的自定义唯一标签? ILifetimeScope仅对父范围实现。有没有没有实现子范围的原因,以便我可以根据HttpContext.Current来使用它们?

有什么想法吗?

谢谢!

1 个答案:

答案 0 :(得分:1)

我认为您拥有的实际上是完全正确的。

  

问题是LifetimeScope的数量与请求的数量一样

这不是问题,这就是它的工作方式。即使是现在进入ASP.NET Core,也不仅仅是Autofac -每个请求的实例意味着每个请求有一个生存期范围。

您有两个选项可以跟踪生存期范围。

首先,您可以将ILifetimeScope注入到任何构造函数中,注入的对象是拥有该对象的生命周期范围。因此,如果您已经注册了InstancePerRequest,那么您只需添加一个ILifetimeScope构造函数参数即可,它可以获取请求范围。

第二,创建时,您始终可以将生存期范围存储在HttpContext.Current 中。

using (var lifetimeScope = AutofacHelper.BeginLifetimeScope())
{
    HttpContext.Current.Items["RequestLifetimeScope"] = lifetimeScope;
    result = InvokeRequest(request.Api, context);
} 

然后,如果您绝对必须获得该范围(例如服务位置),则可以从当前上下文进行操作。

var scope = (ILifetimeScope)HttpContext.Current.Items["RequestLifetimeScope"];
var x = scope.Resolve<IService>();

如果您想要更多有关范围的存储位置,访问方式的指针...,或者甚至要使用某些内置的帮助程序,我都将签出the source for the Autofac WebAPI integration。您可能还想了解Web API本身如何移动请求范围-它stores the scope along with the inbound request message,因此您可以调用message.GetDependencyScope()并获取当前的生存期范围。您可以做类似的事情。

如果您使用的是OWIN管道,那么OWIN integration for WebAPI, too可能会给您一些有关如何连接事物的想法。