Вам придется управлять своими собственными 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, потому что он будет удален в конце запроса. Вы можете разрешить именованную область действия, которая будет корнем всей области действия вашей очереди.
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, чтобы упростить задачу.
person
Cyril Durand
schedule
30.03.2020