Autofac范围生命周期问题

问题描述 投票:4回答:4

我有ASP.NET MVC应用程序,我在其中注册了一个带有InstancePerHttpRequest范围的组件。

builder.RegisterType<Adapter>().As<IAdapter>().InstancePerHttpRequest();

然后我有一个异步的代码片段,我正在解析适配器组件。

以下代码已简化

Task<HttpResponseMessage> t = Request.Content.ReadAsMultipartAsync(provider).ContinueWith(t =>

      // IHandleCommand<T> takes an IAdapter as contructor argument
      var h = DependencyResolver.Current.GetServices<IHandleCommand<T>>();
);

上面的代码抛出异常:The request lifetime scope cannot be created because the HttpContext is not available.

所以我做了一些关于这个主题的研究,发现这个答案https://stackoverflow.com/a/8663021/1003222

然后我将解析代码调整为此

 using (var c= AutofacDependencyResolver.Current.ApplicationContainer.BeginLifetimeScope(x => x.RegisterType<DataAccessAdapter>().As<IDataAccessAdapter>).InstancePerLifetimeScope()))
 {
       var h = DependencyResolver.Current.GetServices<IHandleCommand<T>>();
 }

但例外保持不变。 The request lifetime scope cannot be created because the HttpContext is not available.

我错过了什么吗?

autofac
4个回答
4
投票

你可以尝试这样的事情:

using (var c= AutofacDependencyResolver.Current
                                       .ApplicationContainer
                                       .BeginLifetimeScope("AutofacWebRequest"))
{
   var h = DependencyResolver.Current.GetServices<IHandleCommand<T>>();
}

2
投票

Autofac尝试从MVC依赖关系解析器解析容器,如果您有异步操作,httpContext将不可用,因此DependencyResolver也不可用。

一个选项是使容器在静态变量或适当的实例中可用,并为此操作创建上下文范围。

public static IContainer Container

完成构建器设置后,复制容器

public class ContainerConfig
{
    public static IContainer Container;
    public static void RegisterComponents()
    {
        var builder = new ContainerBuilder();
        builder.RegisterInstance(new Svc()).As<ISvc>();
        Container = builder.Build();
        DependencyResolver.SetResolver(new AutofacDependencyResolver(Container ));
    }
}    

然后在解析时使用静态容器配置来创建所需的实例。

using (var scope = ContainerConfig.Container.BeginLifetimeScope())
{
       result = ContainerConfig.Container.Resolve<T>();
}

希望能帮助到你


1
投票

如果您无权访问System.Web.Http,则无法使用DependencyResolver.Current。您需要存储容器并从中解析依赖关系:

//On Startup Class
public static IContainer Container { get; private set; }

public void Configuration(IAppBuilder app)
{
   ...
   var builder = new ContainerBuilder();
   builder.RegisterModule([yourmodules]);
   ...
   var container = builder.Build();
   Container = container;
}

然后,当您需要您的实例时:

using (var scope = Container.BeginLifetimeScope())
{                                
   YourInterfaceImpl client = Container.Resolve<YourInterface>();
   ...
}

希望这有帮助!


1
投票

在我的例子中,我在WebAPI启动时实例化所有类型,以尽早捕获任何故障。那时,没有请求,所以对于注册为InstancePerRequest的类型,我收到此错误:

从请求实例的范围中看不到带有与“AutofacWebRequest”匹配的标记的范围

基于@ KozhevnikovDmitry的回答,这就是我如何运作:

using (var scope = container.BeginLifetimeScope("AutofacWebRequest"))
{
    foreach (Service item in container.ComponentRegistry.Registrations.SelectMany(x => x.Services))
    {
        Type type = item is TypedService ts ? ts.ServiceType
                  : item is KeyedService ks ? ks.ServiceType
                  : throw new Exception($"Unknown type `{item.Description}`");
        try
        {
            scope.Resolve(type);
        }
        catch (Exception ex)
        {
            _log.Debug($"Error instantiating type `{type.FullName}`", ex);
            throw;
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.