两个(几乎)并发 DbContext 导致问题:如何在 Controller 和 AuthorizeAttribute 之间共享

Posted

技术标签:

【中文标题】两个(几乎)并发 DbContext 导致问题:如何在 Controller 和 AuthorizeAttribute 之间共享【英文标题】:Two (almost) concurrent DbContexts causing problems: How to share between Controller and AuthorizeAttribute 【发布时间】:2014-01-31 22:07:27 【问题描述】:

每隔一段时间,我都会在我的 ASP.NET/MVC5/WebAPI2/EF6/MSSQL 应用程序中遇到以下异常:

System.InvalidOperationException:创建模型时无法使用上下文。如果在 OnModelCreating 方法中使用上下文,或者多个线程同时访问同一个上下文实例,则可能会引发此异常。请注意,不保证 DbContext 和相关类的实例成员是线程安全的。

我已经将此追溯到我的授权代码,它是AuthorizeAttribute 的派生代码,并实例化了它自己的DbContext 以验证我的Web API 使用者的API 密钥是否有效(尝试访问数据库时发生错误) .

AuthorizeAttribute 反过来装饰控制器,这些控制器是我的 BaseController 的派生,实例化 DbContext 用于控制器工作。

在尝试解决此问题几天并阅读this 和this 之后,我怀疑每个请求创建两个DbContext 实例是问题所在。但是,我不太确定如何只使用一个实例来完成这项工作。我的控制器代码目前很好地实例化 DbContext 在自己创建时,并在控制器本身处理时透明地处理它。 AuthorizeAttribute 完全独立于这一切,并根据自己的目的创建上下文。

任何模式/想法如何为两个工作单元保留/重用相同的DbContext

【问题讨论】:

我从来没有遇到过这种问题,我使用的方法和你差不多。你介意提供一些代码吗? OnModelCreating 在每次应用程序启动时仅调用一次 - 如果您在 Web 应用程序的启动代码中强制 DbContext 初始化会发生什么情况。更好的是 - 如果您使用 IIS 7.5 或更高版本,您应该能够立即运行启动代码,而无需请求触发它。 【参考方案1】:

我在第一次使用 Entity Framework 6 的基础应用程序开始时遇到了完全相同的问题。

对我来说最好的解决方案是使用 Autofac(与 MVC 集成)和 Autofac 的 InstancePerRequest 生命周期范围确保在请求生命周期中只有一个 DbContext 实例。

如果您有兴趣采用依赖注入路线(我强烈建议您这样做),我建议您熟悉 Autofac - 有关您的特定问题的更多信息,请查看 davidbitton 的回答 here - 它会得到你在正确的轨道上。

【讨论】:

以上是关于两个(几乎)并发 DbContext 导致问题:如何在 Controller 和 AuthorizeAttribute 之间共享的主要内容,如果未能解决你的问题,请参考以下文章

如何处理数据加载器/GraphQL 嵌套查询中的并发 DbContext 访问?

EF DbContext 并发执行时可能出现的问题

在entity framework中,DbContext是否需要手动Dispose ?

如何为 DbContext 设置 CommandTimeout?

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

实现通用 DbContext 服务