Внедрение зависимостей ядра.net в размещенный сервис
Моему основному приложению aspnet необходимо сканировать данные за указанный промежуток времени. Я выбрал реализацию IHostedService, чтобы запустить его параллельно с API. Этот размещенный сервис нуждается во внедрении некоторых сервисов. Сейчас я регистрирую их при запуске, но получаю эту ошибку:
System.InvalidOperationException: "Невозможно использовать службу" IXService "с областью действия из одноэлементного Microsoft.AspNetCore.Hosting.Internal.HostedServiceExecutor".
Мой startup.cs:
services.AddScoped<IXService, XService>();
services.AddHostedService<MyHostedService>();
У меня была похожая проблема с DbContext, я решил ее с помощью /questions/42586504/kak-ya-dolzhen-vnedrit-ekzemplyar-dbcontext-v-ihostedservice/42586514#42586514, но на этот раз мне нужно внедрение зависимостей, проходящее через более глубокие слои и имеющее дело с IServiceScopeFactory в каждом из них, кажется, элегантное решение.
1 ответ
Причина, по которой вам не разрешено делать это, заключается в том, что MyHostedService имеет одноэтапное время жизни, которое является более продолжительным, чем область действия. Основное допущение здесь заключается в том, что сервис, зарегистрированный в качестве области действия, не должен сохраняться в течение неопределенного времени, это может легко произойти, если одноэлементная служба сохраняет ссылку на службу области.
Я думаю, что решение, которое вы ищете, состоит в том, чтобы внедрить IServiceProvider в MyHostedService, использовать его для создания новой области и нового экземпляра XService всякий раз, когда вам это нужно.
То есть заменить
_xService.Foo();
с
using(var scope = _serviceProvider.CreateScope()) {
var xService = scope.ServiceProvider.GetService<IXService>();
xService.Foo();
}
Альтернативой, конечно, было бы просто зарегистрировать XService в качестве одиночного, просто заменив вызов AddScoped на AddSingleton, но я бы не рекомендовал его.
Изменить: я должен признать, что не читал вашу ссылку, прежде чем публиковать мой ответ. Тем не менее, я все еще думаю, что это самое элегантное решение.