【问题标题】:Autofac not working with background tasksAutofac不适用于后台任务
【发布时间】:2015-11-11 19:07:22
【问题描述】:

我有一个任务需要在后台的单独线程中运行,我正在使用 SignalR 报告进度。这在前段时间有效,并且我对代码进行了一些修改,但是对于现在收到的错误,我完全不知所措:

“从请求实例的范围中看不到带有与“AutofacWebRequest”匹配的标记的范围。这通常表示注册为 per-HTTP 请求的组件正在由 SingleInstance() 组件(或类似的场景。)在 Web 集成下,始终从 DependencyResolver.Current 或 ILifetimeScopeProvider.RequestLifetime 请求依赖项,而不是从容器本身请求依赖项。”

非常感谢任何帮助!

    public ActionResult DoAction(IEnumerable<string> items){

    //...
    Func<CancellationToken, Task> taskFunc = CancellationToken => performAction(items);
    HostingEnvironment.QueueBackgroundWorkItem(taskFunc);
    //...
    }

    private async Task performAction(IEnumerable<string> items){
    var svc = AutofacDependencyResolver.Current.AppicationContainer.BeginLifetimeScope().Resolve<MyService>();
    svc.Method(items);
    }

public class MyService{
   private EntityContext db;

   public MyService(EntityContext db){

   this.db = db;
   }
}

在我的 Startup.Container.cs 文件中:

builder.RegisterType<MyService>().As<MyService>().InstancePerLifetimeScope();
   builder.RegisterType<EntityContext>().InstancePerRequest();

【问题讨论】:

标签: c# autofac


【解决方案1】:

我最近在answeranswer 的帮助下实现了类似的功能。您需要创建一个新的生命周期范围 - 这听起来像是您在 Web 应用程序中执行此操作,因此您需要通过 per-request 标记创建范围(示例如下)。

另一个(非 StackOverflow)answer 提供了类似的建议。

public Task Run<T>(Action<T> action)
{
    Task.Factory.StartNew(() =>
    {
        using (var lifetimeScope = _container.BeginLifetimeScope(MatchingScopeLifetimeTags.RequestLifetimeScopeTag))
        {
            var service = lifetimeScope.Resolve<T>();
            action(service);
        }
    });
    return Task.FromResult(0);
}

【讨论】:

【解决方案2】:

我做了类似于@Chima Osuji 的事情,但我认为他的回答有些不对劲,所以我将描述我的解决方案并进行解释。

    public class BackgroundTaskFactory : IBackgroundTaskFactory
    {
        private ILifetimeScope lifetimeScope;

        public BackgroundTaskFactory(ILifetimeScope lifetimeScope)
        {
            this.lifetimeScope = lifetimeScope;
        }

        public Task Run<T>(Action<T> action)
        {
            Task task = Task.Factory.StartNew(() =>
            {
                using (var lifetimeScope = this.lifetimeScope.BeginLifetimeScope())
                {
                    var service = lifetimeScope.Resolve<T>();
                    action(service);
                }
            });

            return task;
        }
    }
  1. 重要的是要指出我的 Run 方法正在返回在 Task.Factory.StartNew 上创建的任务。这样,有人等待结果,他就会得到正确的任务。在其他解决方案中,他们返回 Task.FromResult(0) ,它返回一个虚拟任务。

  2. BeginLifetimeScope 创建一个新作用域作为注入作用域的子作用域。如果注入的作用域是与 Web 请求关联的 InstancePerLifetimeScope,则一旦 Web 请求作用域被释放,这个新作用域也将被释放,并且会出错。子作用域的寿命不能超过其父作用域。解决方案? 将 BackgroundTaskFactory 注册为单例。当你这样做时,注入的生命周期范围将是根范围,直到应用程序被释放后才会被释放。

    containerBuilder.RegisterType() .As() .SingleInstance();

【讨论】:

    【解决方案3】:

    基于上述代码的更新答案:

    用法:

    public class ServiceModule :Autofac.Module
    {
        protected override void Load(ContainerBuilder builder)
        {
    
            builder.RegisterType<AutoFac.AsyncRunner>().As<AutoFac.IAsyncRunner>().SingleInstance();
        }
    }
    
    
    public class Controller
    {
    private AutoFac.IAsyncRunner _asyncRunner;
    
    public Controller(AutoFac.IAsyncRunner asyncRunner)
    {
    
        _asyncRunner = asyncRunner;
    }
    
    public void Function()
    {
        _asyncRunner.Run<IService>((cis) =>
       {
           try
           {
              //do stuff
           }
           catch
           {
               // catch stuff
               throw;
           }
       });
    }
    }
    

    界面:

    public interface IAsyncRunner
    {
        Task Run<T>(Action<T> action);
    }
    

    班级:

    public class AsyncRunner : IAsyncRunner
    {
        private ILifetimeScope _lifetimeScope { get; set; }
    
        public AsyncRunner(ILifetimeScope lifetimeScope)
        {
            //Guard.NotNull(() => lifetimeScope, lifetimeScope);
            _lifetimeScope = lifetimeScope;
        }
    
        public Task Run<T>(Action<T> action)
        {
            Task.Factory.StartNew(() =>
            {
                using (var lifetimeScope = _lifetimeScope.BeginLifetimeScope(MatchingScopeLifetimeTags.RequestLifetimeScopeTag))
                {
                    var service = lifetimeScope.Resolve<T>();
                    action(service);
                }
            });
            return Task.FromResult(0);
        }
    
    
    }
    

    【讨论】:

      猜你喜欢
      • 2020-10-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-02-23
      • 1970-01-01
      • 1970-01-01
      • 2020-10-30
      • 2012-05-12
      相关资源
      最近更新 更多