Я перемещаю приложение asp. net mvc5, используя EF6, в asp. net core MVC 3.0, используя EF Core.
В моем приложении mvc5 у меня есть некоторые административные операции которые изменяют базу данных и занимают много времени, поэтому я использую шаблон, когда создаю новый DBContext, который не связан с контекстом запроса, а затем запускаю задачу в фоновом режиме с помощью Task.Run. Это работало отлично в течение многих лет.
При преобразовании в ядро. net было неясно, как создать новый DBContext так, как я делал это в своей старой кодовой базе. Кажется, что я должен быть в состоянии создать Transient DBContext в этих случаях, и все должно быть в порядке.
Поэтому я создал подкласс MyDbContext с именем MyTransientDbContex и в своем классе Configure добавил эту службу:
services.AddDbContext<MyTransientDbContex>(options =>
options.UseSqlServer(
context.Configuration.GetConnectionString("MyContextConnection")),
ServiceLifetime.Transient, ServiceLifetime.Transient);
В моем контроллере я вставляю контекст в действие, которому требуется временный сервис, и порождаю поток, чтобы что-то с ним сделать:
public ActionResult Update([FromServices] MyTransientContext context) {
Task.Run(() =>
{
try {
// Do some long running operation with context
}
Catch (Exception e) {
// Report Exception
}
finally {
context.Dispose();
}
}
return RedirectToAction("Status");
}
Я не ожидал, что мой переходный контекст будет удален до наконец блок. Но я получаю это исключение при попытке доступа к контексту в фоновом потоке:
Cannot access a disposed object. A common cause of this error is disposing a context that was resolved from dependency injection and then later trying to use the same context instance elsewhere in your application. This may occur if you are calling Dispose() on the context, or wrapping the context in a using statement. If you are using dependency injection, you should let the dependency injection container take care of disposing context instances.
Object name: 'MyTransientContext'.'
И действительно, для объекта контекста установлен флаг _disposed true.
Я поставил точку останова на конструкторе для MyTransientContext и «Сделал идентификатор объекта» этого указателя, чтобы я мог отслеживать объект. Этот временный объект создается и является тем же, который вводится в действие моего контроллера. Это также тот же объект, на который я пытаюсь ссылаться, когда генерируется исключение.
Я попытался установить точку останова данных на элементе _disposed, чтобы вызвать стек вызовов, когда для disposed установлено значение true, но точка останова не будет привязана.
Я также попытался переопределить метод Dispose для MyTransientContext, и он не вызывался до тех пор, пока мое явное удаление не будет выполнено в блоке finally, который происходит после того, как исключение было сгенерировано и перехвачено.
Я чувствую, что мне здесь не хватает чего-то фундаментального. Разве не для этого нужны временные сервисы? Что бы избавиться от службы Transient?
Одна последняя деталь - MyTransientContext является производным от MyContext, который, в свою очередь, является производным от IdentityDbContext (Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityDbContex)
Редактировать: Причина, по которой я пошел по пути использования Transient, была из-за этой базовой страницы документа: https://docs.microsoft.com/en-us/ef/core/miscellaneous/configuring-dbcontext. В нем говорится, что «... любой код, который явно выполняет несколько потоков параллельно, должен гарантировать, что экземпляры DbContext никогда не будут доступны одновременно. Используя внедрение зависимостей, это может быть достигнуто либо путем регистрации контекста в качестве области действия, либо создания областей (с использованием IServiceScopeFactory) для каждого потока или путем регистрации DbContext в качестве переходного (используя перегрузку AddDbContext, которая принимает параметр ServiceLifetime). "
Как указывало xabikos, это может быть переопределено областью действия asp. net Система DI, где все выглядит так, как будто все, что создано этой системой, ограничено контекстом запроса, включая временные объекты. Может кто-нибудь указать, где это задокументировано, чтобы я мог лучше понять, как работать с ограничениями?