【问题标题】:MVC Multiple AJAX Requests with Entity Framework causes error带有实体框架的 MVC 多个 AJAX 请求导致错误
【发布时间】:2012-03-09 00:22:12
【问题描述】:

我有两个 jqGrid,它们通过 ajax POST 调用向我的控制器加载数据,每次运行应用程序时,两个 POST 中只有一个成功执行。通常,如果我在浏览器上点击刷新,两个网格都会正确加载。但始终有 1 个在每个视图的第一次加载时失败(我有两个视图/页面,每个视图/页面都有 2 个 jqGrid,“仪表板样式”)。在 log4net 日志中,这两个请求具有不同的线程,一个总是失败,而另一个成功,但哪个成功是随机的(可能是先到先得)......有时我在尝试迭代时遇到空引用错误结果可枚举的项目列表,其他时候我得到“连接没有关闭。连接的当前状态是正在连接。”

我怀疑这可能是什么原因:启用了 EF 延迟加载/代理、错误的 Windsor 配置、未抛出或显示在堆栈跟踪中的自动映射器错误。但由于我真的不知道,下面是我的设置,以防它有助于破译这个。

持久性 [LifestyleSingleton] - 保存 EF4 数据上下文(代码优先)和对 EF4.3 的引用。有一个工厂用于创建名为 GetContext() 的上下文,该工厂实现了 IDisposable。
Repo [LifestylePerWebRequest] - 它包含实现存储库和规范模式的存储库 (http://huyrua.wordpress。 com/2010/07/13/entity-framework-4-poco-repository-and-specification-pattern/)。
服务 [LifestylePerWebRequest] - 调用 repo 并应用总线逻辑,即返回 PagedList 对象以进行 UI 分页。
Controllers [LifestyleTransient] - mvc 控制器,利用 automapper 映射到视图模型类型。
MVC UI - I我正在实现 Lib.Web.MVC,它为 jqGrid 创建了一个强类型的包装器。从这里开始,我使用 Windsor 容器进行 DI。

更新:我更改了所有组件以向 LifestylePerThread 注册,并且所有错误似乎都已解决。但是,我不明白为什么..我是 DI 的新手,所以我确定我错过了一些东西。 有人能解释一下为什么这解决了这个问题吗? 就可扩展性而言,这种变化会起到什么作用......?我想我希望上下文工厂连同上下文本身一起注册为单例,但这显然是不正确的。

【问题讨论】:

    标签: asp.net-mvc-3 entity-framework entity-framework-4 jqgrid castle-windsor


    【解决方案1】:

    我最近遇到了同样的问题,也是使用 Huy Nguyen 的存储库。我没有使用 Windsor,我看不出 AutoMapper 与此有​​什么关系。

    我通过将MultipleActiveResultSets=True 添加到我的连接字符串来解决它。

    引用微软的“多个活动结果集 (MARS) 是....有多个未完成的默认结果集(firehose 游标),而其他操作可以在同一会话中执行。”

    http://msdn.microsoft.com/en-us/library/ms345109%28v=sql.90%29.aspx了解更多关于火星的信息

    至于您的存储库“生活方式”,我建议每次请求时都创建一个存储库的新实例。我遇到了每个请求的问题。

    我已经确定这两个线程正在访问相同的上下文,这似乎是一个问题。第一个执行线程没有时间关闭,而第二个线程以相同的上下文结束。

    【讨论】:

    • 我实际上在开发的早期就遇到了这个障碍,我通过启用 MARS 解决了它。那么我应该将存储库和服务类设置为 LifestyleTransient() 吗?
    • 我也同意这一点。您也不应该通过应用程序或“通过 Web 请求”来实例化存储库。但是,我们有一个服务层,我们将在服务调用中使用相同的存储库,如果知道所有 get 都在服务请求结束时处理是安全的。数据上下文创建可能会变得很昂贵,如果您从 1 个存储库加载然后尝试将其保存在另一个存储库中(附加/分离/setobjectstate),您可能会遇到大问题。
    【解决方案2】:

    正如我之前提到的,我在使用同一个存储库时遇到了相同的问题。我想我已经使用我在 Huy Nguyen(存储库的作者)博客上的 post 中找到的解决方案解决了这个问题。

    ....当我在一个批处理过程中使用这个存储库时,多个 线程正在访问存储库以及简单的 objectcontext 存储,我得到了异常,因为 objectcontext 不能 共享(因此,EF 本身不是线程安全的)。所以, 似乎对 SimpleObjectContextStorage 稍作修改 现在也可以工作:我只是将存储变量设为 threadstatic 并在其他方法中使用了该属性(_storage 是 每个线程重复,但仅通过第一个线程填写 静态构造函数调用)[ThreadStatic]私有静态字典 _存储;

    私有静态字典存储 { 获取 { 返回 _storage ?? (_贮存 = 新字典());注意:ThreadStatic 期望相应的变量也是静态的,但是因为您通常只定义一个 每个应用程序通过 ObjectContextManager.Init 调用存储,这不应该 有影响。

    【讨论】:

      【解决方案3】:

      它是如何失败的?即你得到一个例外吗?您是否使用诸如 firebug 之类的东西来查看返回的内容?

      会话将被锁定,并且只会处理少量的串行请求,因此如果您的并发请求中涉及会话,您也可能会遇到问题。

      编辑:作为基本规则,如果有任何事情导致您的存储库被实例化并且数据上下文在请求之间保持未处理,那么这是一件非常非常糟糕的事情。我已经看到很多 IOC 容器通过配置或绑定到应该是每个请求的东西来让这种情况太容易发生。

      检查您的堆栈跟踪并检查存储库构造函数是否没有被引导到应用程序范围。这也将导致失去线程安全性...在现成的依赖注入中很常见,为什么我要自己编写以便知道发生了什么。

      我遇到的场景here

      PS:如果您通过 ajax 发布 2 个单独的帖子,那么您不需要多个活动结果集,这表明您的 repo 和/或 datacontext 超出了请求范围。如果您想在同一请求范围内创建相同数据上下文的 2 个实例,则只需要多个活动结果集。

      如果是单个帖子/请求,那么上面的答案可能是正确的。

      【讨论】:

      • 我已经全局应用了 errhandler 过滤器,所以我的 ajax 操作引发了我更新过帐的异常。我不确定你所说的“会话将锁定”是什么意思,你能详细说明一下吗?我还没有使用任何会话变量,但这是否意味着如果我使用会话变量我无法进行并发/异步没有锁定问题的请求?
      • 哦,返回只是内部服务器错误。没有来自 jqGrid onError 事件的详细信息。
      • 是的,如果启用了会话,那么框架将序列化您的传入请求。当处理来自会话的多个请求时,正在运行的请求将阻塞其他请求直到完成。要解决此问题,您必须使用异步控制器。请参阅这篇 MS 文章以获得良好的概述,msdn.microsoft.com/en-us/library/ee728598.aspx
      猜你喜欢
      • 2014-03-20
      • 1970-01-01
      • 2018-10-26
      • 1970-01-01
      • 2020-04-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多