微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

ASP.NET会话对象中的实体框架对象上下文?

我们有一个多层的Asp.NET Web窗体应用程序.数据层有一个名为DataAccess的类,它强制使用Idisposable,并将我们的实体框架对象上下文的实例作为私有字段.该类有许多公共方法返回各种实体集合,并在处理时将处置其对象上下文.

由于我们一直面临的许多问题,我们认为在服务器上保持对象上下文(或DataAccess实例)的范围更长是一个很大的优势.建议将实例保留在this post的HttpContext.Current.Items集合中,以便每个Http请求有一个实例.

我想知道的是:在HttpContext.Current.Session对象中存储我们的对象上下文的实例会产生什么问题/顾虑/问题?

>我假设Session对象已完成并在用户会话到期时设置为垃圾回收,因此实例将正确处理.
>我假设大多数认浏览器设置都会让我们的应用程序放置其SessionId cookie而不会有任何疑虑.
>对象上下文将要处理的数据量不是很大,并且不会对我们体面的服务器硬件造成问题,关于随时间缓存和相对较少的并发用户.

这将相对快速地实施,并且不会影响我们现有的许多单元测试.

我们将使用AutoFac和ServiceProvider类来提供实例.当需要ObjectContext的实例时,它将由类似于此的代码返回:

private static Entities GetEntities(IContext context)
{
    if (HttpContext.Current == null)
    {
        return new Entities();
    }

    if (HttpContext.Current.Session[entitiesKeyString] == null)
    {
        HttpContext.Current.Session[entitiesKeyString] = new Entities();
    }

    return (Entities)HttpContext.Current.Session[entitiesKeyString];
}

干杯.

解决方法

在会话状态下存储ObjectContext不是我认为是一种好的做法,因为该类旨在封装工作单元模式 – 您加载一些数据(实体),修改它们,提交您的更改(由UOW跟踪,然后你就完成了它. UOW对象并非旨在或设计为长期使用.

也就是说,它可以在不引起任何重大灾难的情况下完成,你只需要确保你了解幕后发生的事情.如果您计划这样做,请继续阅读,以便您知道自己正在做什么,并了解权衡取舍.

I’m assuming that the Session object is finalised and set for garbage collection when a user’s session expires,so the instance will be disposed properly.

这实际上是不准确的,或者至少似乎是基于它的措辞.会话到期/注销不会立即导致任何项目被处置.它们最终将被最终确定/处理,但这取决于垃圾收集器,并且您无法控制它何时发生.这里最大的潜在问题是,如果你碰巧在ObjectContext上手动打开一个连接,它不会自动关闭 – 如果你不小心,你最终可能会泄漏数据库连接,这是一个不会被定期发现的东西单元测试/集成测试/实时测试.

The amount of data the Object Context will be dealing with is not enormous and will not pose a problem for our decent server hardware,with regards to caching over time and relatively few concurrent users.

请记住,增长是无限的.如果特定用户决定使用您的网站连续12个小时全天运行不同的查询,那么上下文将不断变得越来越大. ObjectContext没有自己的内部“垃圾收集”,它不会清除长时间未使用的缓存/跟踪实体.如果您确定根据您的使用情况确定这不会是一个问题,那么很好,但是应该困扰您的主要事情是您无法控制情况.

一个问题是线程安全. ObjectContext不是线程安全的.会话访问通常是序列化的,因此一个请求将阻止等待其会话状态,直到完成对同一会话的另一个请求.但是,如果有人决定稍后进行优化,特别是页面级只读会话的​​优化,请求将不再拥有独占锁定,并且您可能最终遇到各种竞争条件或重新入侵问题.

最后但并非最不重要的当然是多用户并发问题. ObjectContext永远缓存它的实体,直到它被释放.如果另一个用户在他自己的ObjectContext上更改了相同的实体,则第一个ObjectContext的所有者将永远不会知道该更改.这些陈旧的数据问题可能非常难以调试,因为您实际上可以查看查询数据库并返回新数据,但ObjectContext将使用已经在缓存中的旧的陈旧数据覆盖它.在我看来,这可能是避免长期存在的ObjectContext实例的最重要原因;即使你认为你已经将它编码为从数据库获取最新数据,ObjectContext也会决定它比你更聪明,而是将你的旧实体交给你.

如果您意识到所有这些问题并已采取措施来缓解这些问题,那很好.但我的问题是,为什么你认为会话级ObjectContext是如此的好主意呢?创建ObjectContext实际上是一个非常便宜的操作,因为元数据是为整个AppDomain缓存的.我猜赌你要么错误地认为它很贵,或者你试图在几个不同的网页上实施复杂的有状态进程,而后者的长期后果远比任何具体的都要糟糕.只需将ObjectContext放入会话即可对您造成伤害.

无论如何你要继续这样做,只要确保你出于正确的理由这样做,因为没有很多理由这样做.但是,正如我所说,这绝对是可能的,你的应用程序不会因此而爆炸.

更新 – 对于其他任何考虑低估这一点的人,因为“同一会话上的多个请求可能导致线程安全问题”,请阅读ASP.NET Session State Overview文档的底部.不仅是序列化的会话状态的单独访问;任何获取会话的请求都会保留对整个请求完成之前未释放的会话的独占锁定.除了上面列出的一些优化之外,在认配置中不可能有两个同时发出的请求,这些请求持有对ObjectContext的同一会话本地实例的引用.

由于上面列出的几个原因,我仍然不会将ObjectContext存储在会话状态中,但除非您将其设置为一个,否则它不是线程安全问题.

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐