Ще трябва да управлявате свой собствен 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