【发布时间】:2020-06-03 04:57:13
【问题描述】:
我正在将使用 EF6 的 asp.net mvc5 应用程序移动到使用 EF Core 的 asp.net core MVC 3.0。
在我的 mvc5 应用程序中,我有一些修改数据库的管理操作需要很长时间,所以当我创建一个与请求上下文无关的新 DBContext 然后运行任务时,我使用了一种模式在后台使用 Task.Run。这多年来一直运行良好。
在转换为 .net 核心时,不清楚如何以我在旧代码库中的方式创建新的 DBContext。看来我应该能够在这些情况下创建一个 Transient DBContext 并且一切都应该没问题。
所以我创建了一个名为 MyTransientDbContex 的 MyDbContext 子类,并在我的 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");
}
我不希望我的瞬态上下文在 finally 块之前被释放。但是在尝试访问后台线程上的上下文时出现此异常:
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 的构造函数上放置了一个断点,并为 this 指针“创建了一个对象 ID”,以便我可以跟踪该对象。正在创建此瞬态对象,并且与注入到我的控制器操作中的对象相同。它也是我在抛出异常时尝试引用的同一对象。
我尝试在 _disposed 成员上设置数据断点,以便在设置为 true 时启用调用堆栈,但断点不会绑定。
我还尝试覆盖 MyTransientContext 上的 Dispose 方法,直到我在 finally 块中显式 dispose 才调用它,这是在抛出并捕获异常之后。
我觉得我在这里遗漏了一些基本的东西。这不是临时服务的用途吗?什么会处理 Transient 服务?
最后一个细节 - MyTransientContext 派生自 MyContext,而 MyContext 又派生自 IdentityDbContext (Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityDbContex)
编辑:我之所以选择使用 Transient 是因为这个 ef 核心文档页面:https://docs.microsoft.com/en-us/ef/core/miscellaneous/configuring-dbcontext。它指出“......任何显式并行执行多个线程的代码都应确保不会同时访问 DbContext 实例。使用依赖注入,这可以通过将上下文注册为作用域并创建作用域(使用 IServiceScopeFactory)来实现对于每个线程,或者通过将 DbContext 注册为瞬态(使用带有 ServiceLifetime 参数的 AddDbContext 的重载)。”
正如 xabikos 所指出的,这似乎被 asp.net DI 系统的范围覆盖,看起来该系统创建的任何内容都被限定为请求上下文,包括瞬态对象。有人可以指出记录在哪里,以便我更好地了解如何处理这些限制吗?
【问题讨论】:
标签: .net-core dependency-injection asp.net-core-mvc entity-framework-core