在 application_endrequest 上处理对象上下文
Posted
技术标签:
【中文标题】在 application_endrequest 上处理对象上下文【英文标题】:disposing object context on application_endrequest 【发布时间】:2012-06-08 11:26:18 【问题描述】:我遇到了我存储在 HttpContext.Current.Items 中的 EF4 对象上下文的问题,然后想在请求得到完全处理后立即处理。
在 Aplication_EndRequest 事件中,我调用 RepositoryContext 的 Terminate() 方法,该方法将从 HttpContext.Current.Items 集合中找到活动的 ObjectContext,然后调用 Close() 在它的连接上和 Dispose() 在它上面。
问题是有时我的某个页面会出现奇怪的行为。在某些情况下,我会收到一条错误消息:
ObjectContext 实例已被释放,不能再用于需要连接的操作
我认为这可能会发生,因为不仅页面请求在完成后会调用 Application_EndRequest 事件,而且还会调用图像请求等,因此有时其他请求可能会在主页请求 ObjectContext 完成工作之前对其进行处理,但这不应该发生,因为一切都是在集合 HttpContext.Current.Items 上进行的,这当然不会在 HTTP 请求之间共享。
另外,从研究来看,这可能是由于某些数据库请求的延迟加载引起的,但这里不应该是这种情况,因为我没有在代码的其他任何地方调用 Dispose(我已经检查过),因此 Dispose() on EndRequest 应该只在一切完成时才被调用,不是吗?
关于可能导致此问题的任何想法?我该如何测试它?你有什么建议?
谢谢!
【问题讨论】:
收到此错误时堆栈跟踪是什么样的? 你能贴出你的 RepositoryContext 类的代码吗? 这里是跟踪:img850.imageshack.us/img850/3210/erroryourate.jpg 似乎是因为在操作过程中对象上下文正在被释放。但是,如果我只在 Application_EndRequest 上进行处理,我仍然不明白这是怎么发生的。 当我尝试访问某个实体的导航属性时,这似乎只发生在静态扩展方法中。 【参考方案1】:这意味着已经在 ObjectContext 上调用了 Dispose()。发生这种情况的原因有很多,但归结为在 Application_EndRequest 之前调用 Dispose() 的事实。如果没有所有的来源,就不可能确切地说出原因。
因为您是在寻求建议,所以我首先将 ObjectContext 从 HttpContext 中取出。数据库连接应该只存在很短的时间,并执行特定的任务。如果它是短暂的,您可以将 ObjectContext 放在 using 语句中,该语句会自动为您调用 Dispose()。
【讨论】:
我认为请求的时间还可以。这种模式继承自 NHibernate,称为 open-session-in-view。它工作正常。 如果不将 ObjectContext 放在 HttpContext 中,没有什么可以阻止打开视图中的会话。 ViewModel 将知道如何在 View 被呈现时执行操作以访问数据库。拥有每个请求的上下文也意味着 SaveChanges() 实际执行的操作并不直观,因为需要审查整个请求生命周期。 好吧,我已经检查并检查并没有从其他任何地方处置,我已经搜索了所有解决方案的源代码上的所有“使用”和所有“处置”,但什么也没有。现在,我只是在做 objectContext.Connection.Close() 而不是 dispose ,这似乎工作正常。顺便说一句,这只发生在导航属性上,不会发生其他任何事情。 @sagi 你有没有找到另一个解决方案?我看到你描述的同样的问题。没有其他东西可以尽早处理上下文。每次使用指向返回延迟加载的 IQueryable 结果集的存储库方法的 objectdatasource 时,我都可以重现它。我的 objectdatasource 在 onobjectcreating 事件中从 httpcontext 获取 objectcontext。如果我返回非延迟加载(列表)或根据需要创建对象上下文(而不是将其保存在 httpcontext 中),则工作正常。快把我逼疯了……【参考方案2】:假设您有一个为您提供当前 ObjectContext 的类,那么程序员可能会根据博客或类似内容中的一些示例编写以下代码:
using(var context = ContextProvider.GetCurrentContext())
...
并在请求结束前处理掉 ObjectContext。
如果你想测试 ObjectContext 被放置在哪里,你可以这样做:
在您的 ObjectContext 实现中,将 Dispose 方法更改为:
public override void Dispose()
throw new InvalidOpearationException("Gotcha!");
public void ActuallyDisposePlease()
base.Dispose();
并在 Application_EndRequest 中调用ActuallyDisposePlease() 方法。
当然,这是为了测试/调试/诊断角度,绝不应该投入生产。
【讨论】:
以上是关于在 application_endrequest 上处理对象上下文的主要内容,如果未能解决你的问题,请参考以下文章
NOIP 2015 & SDOI 2016 Round1 & CTSC 2016 & SDOI2016 Round2游记