【发布时间】:2013-04-09 20:25:04
【问题描述】:
我最近对我的 MVC3 应用程序进行了更改,以尝试正确处理 DbContext 对象 [1]。这在开发中效果很好,但是一旦应用程序被推送到我的生产服务器,我开始间歇性地收到一些有趣的异常,这些异常会一直持续到 AppPool 被回收。异常可以追溯到我自定义的AuthorizeAttribute 中的代码,如下所示:
System.InvalidOperationException: The 'Username' property on 'User' could not be set to a 'Int32' value. You must set this property to a non-null value of type 'String'.
System.InvalidOperationException: The 'Code' property on 'Right' could not be set to a 'String' value. You must set this property to a non-null value of type 'Int32'.
(数据库架构如下所示:用户:[Guid, String, ...],权限:[Guid, Int32, ...])
就好像一些“线正在交叉”,并且应用程序正在混合来自数据库的结果:试图将Right 结果具体化为User,反之亦然。
为了管理DbContext 的处置,我将代码放入以将其存储在每个控制器级别。当控制器被处置时,我也处置了DbContext。我知道这很hacky,但AuthorizeAttribute 通过filterContext.Controller 使用相同的上下文。
在这个庄园里处理DbContext的对象生命周期有什么问题吗?关于为什么我得到上面的交叉异常有任何合乎逻辑的解释吗?
[1] 虽然我知道没有必要处置 DbContext 对象,但我最近发现一些消息来源表明无论如何这是最佳做法。
编辑(根据@MikeSW 的评论)
当AuthorizationContext 在范围内时,在OnAuthorization 方法中设置了代表DbContext 的AuthorizeAttribute 属性。该属性随后在AuthorizeCore 方法中使用。
【问题讨论】:
-
你能分享一些你自定义AuthorizeAttribute的相关代码吗?请注意,asp.net mvc 将属性用作单例。你还在使用 DI 容器吗?
-
@MikeSW 我添加了有关上述用法的信息。我没有使用 DI 容器。根据我上面提供的信息,这些错误似乎是由于并发性而发生的:在
OnAuthorization和AuthorizeCore之间的时间里,另一个请求触发了OnAuthorization并破坏了DbContext属性。是这样吗? -
是的,这是你的问题。 [Authorize] 基本上是一个单例,您在每次请求时更改 dbcontext 属性。我建议使用 DI 容器,使用 HttpPerInstance 生命周期注册 DbContext,然后在 OnAuthorization 方法中使用 DependencyResolver.Current.GetService
()。容器也应该处理 DbContext 的处置 -
@MikeSW 我们正在考虑添加一个 DI 容器,但正在寻找替代解决方案。在
OnAuthorization内部的this上使用同步锁会产生任何问题,至少可以在短期内缓解问题吗?只是在我们当前的应用规模下,添加一个 DI Container 并不是一件小事。 -
不,我会使用 DI 容器。这是最简单、最干净的解决方案。 Asp.Net mvc 知道如何使用它,你真的只能用它来解决这个问题。
标签: asp.net-mvc-3 entity-framework-4 dispose dbcontext