如何在后台任务中解决服务? [英] How to resolve services within a background task?

查看:84
本文介绍了如何在后台任务中解决服务?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经按照

I've implemented the BackgroundQueue as explained here. This will replace the old HostingEnvironment. Furthermore, I'm refactoring the code to use Autofac to inject services into the background task.

当前,代码是这样的:

public ActionResult SomeAction()
{
    backgroundQueue.QueueBackgroundWorkItem(async ct =>
    {
        //Need to resolve services here...
    }

    return Ok();
}

backgroundQueue IBackgroundQueue 的实例,并已作为单例向Autofac注册.

backgroundQueue is an instance of IBackgroundQueue and is registered with Autofac as a singleton.

如何将Autofac容器传递给任务,以便我可以注册服务?还是有更好的方法来注册任务中的服务?

How can I pass the Autofac container to the task so I can register the services? Or is there a better way to register services in a task?

一个解决方案可能正在这样做:

A solution might be doing this:

var myService = HttpContext.RequestServices.GetService(typeof(IMyService));

但这被认为是抗专利药.

But this is considered as an anti-patten.

推荐答案

您将必须在任务中管理自己的 LifetimeScope .

You will have to manage your own LifetimeScope inside your task.

最简单的方法是更改​​方法 QueueBackgroundWorkItem 以引入 ILifetimeScope

The easiest way would be to change the method QueueBackgroundWorkItem to introduce a ILifetimeScope

public interface IBackgroundTaskQueue
{
    void QueueBackgroundWorkItem(Func<ILifetimeScope, CancellationToken, Task> workItem);

然后

public ActionResult SomeAction()
{
    backgroundQueue.QueueBackgroundWorkItem(async (scope, ct) =>
    {
        scope.Resolve<IService>().Do()
        //Need to resolve services here...
    }

    return Ok();
}

您可以使用现有范围的 BeginLifetimeScope 获得新的 ILifetimeScope ,并且 ILifetimeScope 是已注册的服务.

You can get a new ILifetimeScope using the BeginLifetimeScope of an existing scope and ILifetimeScope is a registered service.

如果您使用链接提供的 QueueHostedService 实现,则可以按照以下说明进行更改

If you use the QueueHostedService implementation provided by the link you can change it as follow

public class QueueHostedService: IBackgroundTaskQueue {
    public QueueHostedService(ILifetimeScope scope, ...) {
        this._rootScope = scope; 
    }

    private readonly ILifetimeScope _rootScope; 

    ...

     private async Task BackgroundProcessing(...) {
        ... 
        try {
            using(ILifetimeScope queueScope = this._rootScope.BeginLifetimeScope()){
                await workItem(queueScope, stoppingToken);
            }
        }
        ...
     }

如果无法更改方法定义,则可以在任务内创建生命周期范围.您可以在控制器内注入 ILifetimeScope ,但不能从中创建LifetimeScope,因为它将在请求结束时处理.您可以解析一个命名的lifetimescope,它将成为所有队列生存期作用域的根

If you can't change the method definition, you can create the lifetime scope inside the task. You can inject a ILifetimeScope inside the controller but you can't create a LifetimeScope from it because it will be disposed at the end of the request. You can resolve a named lifetimescope which will be the root of all your queue lifetime scope

public class XController {

  public XController(ILifetimeScope scope){
      // you can also inject directly the named scope using named attribute or custom parameter, etc. 
      this._taskRootScope.ResolveNamed<ILifetimeScope>("taskRoot"); 
  }
  private readonly ILifetimeScope _taskRootScope; 


  public ActionResult SomeAction()
  {
    var taskRootScope = this._taskRootScope;
    backgroundQueue.QueueBackgroundWorkItem(async ct =>
    {
      using(var taskScope = taskRootScope.BeginLifetimeScope()){
          taskScope.Resolve<IService>().Do();
      }
    }

    return Ok();
  }
}

注册将类似于

builder.Register(c => c.Resolve<ILifetimeScope>())
       .Named<ILifetimeScope>("taskRoot")
       .SingleInstance(); 

还有很多其他方法可以自己处理范围.

There is lot of other ways to handle the scope by yourself.

下一步可能是使用方法参数注入,如ASP.net核心所做的那样,结果将是这样:

The next step could be to use method parameter injection like what ASP.net core does which will results to something like that :

backgroundQueue.QueueBackgroundWorkItem(async (IService service, CancellationToken ct) =>
{
    //Need to resolve services here...
}

但这需要很多工作

您也可以考虑使用专用的框架,例如 hangfire 来简化事情.

You may also consider using a dedicated framework like hangfire to make things easier.

这篇关于如何在后台任务中解决服务?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆