Вам придется управлять своим собственным LifetimeScope
внутри вашей задачи.
Самый простой способ - изменить QueueBackgroundWorkItem
, чтобы ввести 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();
}
Вы можете получить новый ILifetimeScope
, используя BeginLifetimeScope
существующей области действия, а ILifetimeScope
является зарегистрированной услугой.
Если вы используете реализацию QueueHostedService
, предоставленную ссылкой, вы можете изменить ее следующим образом:
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 из него, потому что он будет удален в конце запроса. Вы можете разрешить именованный жизненный цикл, который будет root всего объема жизни вашей очереди
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();
Существует множество других способов управляйте областью видимости самостоятельно.
Следующим шагом может быть использование инжекции параметров метода, как это делает ядро ASP. net, что приведет к чему-то вроде этого:
backgroundQueue.QueueBackgroundWorkItem(async (IService service, CancellationToken ct) =>
{
//Need to resolve services here...
}
Но это потребует много работы
Вы можете также рассмотреть возможность использования специализированной инфраструктуры, такой как hangfire , чтобы упростить задачу.