防止 DbContext 被释放,直到异步任务完成

Posted

技术标签:

【中文标题】防止 DbContext 被释放,直到异步任务完成【英文标题】:Prevent DbContext from being disposed until async task completes 【发布时间】:2021-10-13 06:23:05 【问题描述】:

我有一个 C# 核心 Web API 控制器(Microsoft.AspNetCore.Mvc.ControllerBase 的实现),它具有 API 方法 A 和 API 方法 B。A 是异步的,会触发并忘记异步工作线程。 B 是同步的。

A(及其工作线程)和 B 都使用实体框架从同一个数据库中读取和写入。但我遇到的问题是 DBContext 对象在 A 的工作线程完成之前被释放。

我知道一次性对象的所有者应该创建和处置它的原则。所以我考虑将 A 的 DBContext 包装在一个不是一次性的 Repository 类中,但这似乎违反了分析器规则:“CA1001:拥有一次性字段的类型应该是一次性的”-https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1001 但是如果我将 Repository 对象设为一次性,Dotnet当 A 返回时(但在其工作线程完成之前),核心会处理它。

我也考虑过将存储库设为单例,但这违反了 DbContext 对象应该是短暂存在的原则。

感谢您提出的任何建议!

【问题讨论】:

是否可以选择使用托管服务?然后托管服务可以拥有自己的 DbContext 实例? @MaartenDev 这是一个有用的建议,但从我所阅读的内容来看,托管服务在服务器的生命周期内运行,显然 DbContext 对象应该是短暂的。当然,我可以拥有一个负责启动工作线程的托管服务,但我认为这让我回到了原点。如果我误解了您的建议,请纠正我。 【参考方案1】:

A 是异步的,会触发并忘记异步工作线程。

那么工作线程不得使用依赖注入管理的Scoped DbContext。相反,它应该在 using 块中创建 DbContext 实例,并在代码中显式管理其生命周期。

【讨论】:

@david-browne-microsoft 但正如我所提到的,VS 坚持我将工人标记为一次性,在这种情况下,工人本身在方法 A 返回时被处置(在工人完成工作之前) . 我建议 DbContext 应该是在 using 块中声明的局部变量,而不是其他 Disposable 类型的成员。 @DavidBrowne-Microsoft 好的,将 DbContext 放在 using 块中是有意义的,但鉴于工作线程在多个方法中使用它,不应该在构造函数中实例化一次并用作类级变量?如果是这样,那不是让我回到开头,带着同样的分析员反对吗? 你可以多次创建/销毁,或者在外部方法中创建并传递给其他方法。

以上是关于防止 DbContext 被释放,直到异步任务完成的主要内容,如果未能解决你的问题,请参考以下文章

操作无法完成,因为 DbContext 已被释放。System.InvalidOperationException

使用 ObjectDataSource.Select() 方法最终会导致异常“操作无法完成,因为 DbContext 已被释放。”

实体框架:如何防止 dbcontext 被多个线程访问?

WCF HandleError System.InvalidOperationException 一个任务只有在它处于完成状态时才能被释放

从同步代码调用异步方法并阻塞直到任务完成的正确方法是啥? [复制]

如何阻塞直到异步作业完成