Autofac范围生命周期问题

时间:2013-02-24 09:04:15

标签: autofac

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

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

然后我有一段异步代码,我正在解析Adapter组件。

以下代码已简化

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.

我错过了什么吗?

4 个答案:

答案 0 :(得分:4)

你可以尝试这样的事情:

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

答案 1 :(得分: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>();
}

希望有所帮助

答案 2 :(得分: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>();
   ...
}

希望这有帮助!

答案 3 :(得分: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;
        }
    }
}