Внедрение зависимостей ядра.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, но я бы не рекомендовал его.

Изменить: я должен признать, что не читал вашу ссылку, прежде чем публиковать мой ответ. Тем не менее, я все еще думаю, что это самое элегантное решение.

Другие вопросы по тегам