Доступ к службе DbContext из фоновой задачи

Таким образом, в приложения ASP.NET Core встроено внедрение зависимостей. А с помощью Entity Framework Core вы можете легко получить экземпляр DbContext с заданной областью действия из метода действия контроллера.

Но все это ограничивается действиями контроллера. Если вам нужно запустить длительную фоновую задачу из действия, которое будет взаимодействовать с представлением в браузере с помощью других средств, таких как WebSocket, тогда у вас внезапно ничего не останется. Фоновая задача не может использовать DbContext действия, потому что он был ограничен и удален при возврате действия.

Простым способом было бы использовать то, что люди называют локатором услуг. Это статическая копия некоторого IServiceProvider для последующего доступа и разрешения службы. (ASP.NET Core 2.1 может потребовать другого подхода, поскольку я читал в этом комментарии.) Но куда бы я ни посмотрел, это описывается как антипаттерн. Это усложняет тестирование и скрывает зависимости. Хорошо.

Итак, какое решение рекомендуется для этого сценария? Я где-то в глуши. Фоновая задача, которая может быть запущена из планировщика вместо действия контроллера. Никаких HTTP-запросов нет. Что DI может здесь сделать для меня? Есть ли решение без возврата к антипаттернам? Я уверен, что создатели ASP.NET Core D я об этом подумали.

Есть ли способ разрешить там службы или изменить мою архитектуру так, чтобы сама фоновая задача каким-то образом выходила из DI?

Обновление: Запрошено в комментарии, пример: действие контроллера что-то запускает. Это займет много времени, как сканирование сети. Представление возвращается с чем-то вроде «Уважаемый пользователь, пожалуйста, подождите, пока вы увидите этот индикатор выполнения». Работа продолжается в фоновом режиме, непрерывно отправляя информацию о ходе и / или результатах в браузер. (Вместо этого браузер может также опрашивать прогресс.) Фоновой задаче требуется доступ к базе данных для хранения результатов сканирования. Когда сканирование завершено, браузер может получить его с помощью другого действия. Поэтому, если бы фоновая задача просто использовала бы DbContext действия контроллера, это стало бы непригодным для использования после завершения действия.

Другой пример - фоновая служба, которая вообще не связана с запросом. Сервис, который регулярно проверяет базу данных, а затем что-то делает. Для этого также нужен DbContext, и некуда даже пытаться его украсть.


person ygoe    schedule 28.07.2018    source источник
comment
Приведите конкретный пример проблемы, с которой вы столкнулись.   -  person Steven    schedule 29.07.2018
comment
@ Стивен Я добавил несколько примеров.   -  person ygoe    schedule 30.07.2018
comment
Извините, мне следовало выразиться более ясно; Я имел в виду примеры кода. Вы можете показать соответствующий код для этого?   -  person Steven    schedule 30.07.2018
comment
У меня нет готового кода для показа. И я не уверен, какой код вам нужно увидеть, я думаю, что описание очень хорошо подходит. Представьте себе действие контроллера и задачу, использующую DbContext. Это все.   -  person ygoe    schedule 30.07.2018


Ответы (1)


В этом случае вы можете полагаться только на шаблон servicelocater-pattern, который является анти-шаблоном. Кроме того, DbContext должен быть зависимым от экземпляра (временным), а не иметь область видимости.

Мое предложение состоит в том, чтобы ввести IServiceScopeFactory, который является одноэлементным, и начать область в фоновом работнике, который выполняет действие.

using (var scope = _serviceScopeFactory.CreateScope())
{
   var context = scope.ServiceProvider.GetRequiredService<DbContext>();
   // now do your work
}

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

Не имеет прямого отношения, но ASP.NET-Core имеет встроенный фоновый рабочий с IHostedService.

Изменить. Как Стивен предположил ниже, это не всегда может быть анти-шаблоном при ручном разрешении / запуске классов. По крайней мере, когда об этом позаботится корень композиции. Вот предоставленная им ссылка, где это довольно хорошо объясняется.

person alsami    schedule 28.07.2018
comment
Я ненавижу педантизм, но то, является ли вызов ServiceProvider.GetService реализацией анти-шаблона Service Locator, зависит от того, какое местоположение он используется. При вызове из корня композиции это не локатор услуг. Но при использовании вне корня композиции это локатор службы. Для получения дополнительной информации см. это. - person Steven; 30.07.2018
comment
Привет, Стивен. Спасибо за ваш отзыв. Я прочту это и соответствующим образом обновлю ответ. - person alsami; 30.07.2018