2

我有两个jqGrid通过ajax POST调用加载数据到我的控制器,每次运行应用程序时,只有一个POST成功执行。通常情况下,如果我点击浏览器刷新,两个网格都会正确加载。但是,在每个视图的第一次加载时,2个中的1个会失败(我有两个视图/页面,每个页面都有2个jqGrid,“仪表板样式”)。在log4net日志中,两个请求有不同的线程,一个总是失败,而另一个成功,但哪一个成功是随机的(可能是先到先得,首次服务)...有时,当我试图迭代通过导致可枚举的项目列表,其他时间我得到“连接未关闭,连接的当前状态正在连接。”MVC多个AJAX请求与实体框架导致错误

我对这可能是什么原因有些怀疑:启用EF延迟加载/代理,错误的windsor配置,未在堆栈跟踪中引发或显示的automapper错误。但是因为我真的没有线索,下面是我的设置,以防止它破译。

持久性 [LifestyleSingleton] - 这包含EF4 datacontext(代码优先)和对EF4.3的引用。有一个工厂用于创建称为GetContext()的Context,并且该工厂实现了IDisposable。
回复 [LifestylePerWebRequest] - 这包含实现存储库和规范模式的存储库(http://huyrua.wordpress.com/2010/07/13/entity-framework-4-poco-repository-and-specification-pattern /)。
服务 [LifestylePerWebRequest] - 调用回购并应用总线逻辑,即返回用于UI分页的PagedList对象。
控制器 [LifestyleTransient] - mvc控制器,利用automapper进行映射查看模型类型。
MVC UI - 我正在实现Lib.Web.MVC,它为jqGrid创建一个强类型的包装器。从这里,我用windsor容器做DI。

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

回答

1

它是如何失败?即你得到一个例外吗?你是否使用类似萤火虫的东西来查看返回的内容?

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

编辑:作为一个基本的规则,如果任何事情导致您的存储库被实例化,并且datacontexts在请求中保持不存在,那么这是非常非常糟糕的事情。我见过很多IOC容器,通过配置或通过绑定到应该按照请求进行的操作,可以很容易地实现这种容器。

检查堆栈跟踪并检查存储库构造函数未被引导到应用程序作用域。这也会导致线程安全性的丧失......非常常见的是现成的依赖性注入以及为什么我写我自己的,所以我知道发生了什么。

情景我遇到here

PS:如果你通过AJAX做2个独立的职位,那么你不应该需要多活动结果集,这是一个迹象,表明你的回购和/或DataContext的是boud外的请求范围。如果要在同一请求范围内创建2个相同的datacontext实例,则只需要多个活动的结果集。

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

+0

我已经应用于全球的errhandler过滤器,那么我的阿贾克斯行动引发异常我已经更新与发布。 我不太确定你的意思是“会话锁定”,你能否详细说明一下?我还没有使用任何会话变量,但这是否意味着如果我使用会话变量我无法发出没有锁定问题的并发/异步请求? – diegohb 2012-03-09 00:56:07

+0

哦,并且返回只是内部服务器错误。没有来自jqGrid onError事件的详细信息。 – diegohb 2012-03-09 01:05:43

+1

是的,如果会话已启用,那么框架将序列化您的传入请求。当处理来自会话的多个请求时,正在运行的请求将阻止其他请求直到完成。要解决这个问题,你必须使用异步控制器。请参阅此MS文章以获取良好的概述,http://msdn.microsoft.com/en-us/library/ee728598.aspx。 – Mark 2012-03-09 19:39:21

3

我最近有同样的问题,也使用Huy Nguyen的存储库。我没有使用Windsor,也没有看到AutoMapper如何处理这件事。

我解决了它,将MultipleActiveResultSets=True添加到我的连接字符串。

引用微软“多活动结果集(MARS)是....简而言之,它是能够在一个给定的SQL Server连接下有多个挂起的请求。对于大多数情况下,这将直接转化为能够有多个默认结果集(流水游标)未完成,而其他操作可以在同一个会话中执行。“

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

至于你的资料库“生活方式”我建议每次都创建一个请求库的新实例。每次请求都有问题。

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

+0

在我的开发中,我实际上遇到了这个障碍,我通过enablind MARS解决了它。那么我应该将资源库和服务类设置为LifestyleTransient()? – diegohb 2012-03-09 19:16:51

+0

我也同意这一点。您不应该通过应用程序或“通过Web请求”实例化存储库。但是,我们有一个服务层,并且如果服务调用中的所有get都放置在服务请求的末尾,那么在安全的情况下,我们将使用同一个存储库。 Datacontext的创建可能会变得昂贵,如果您从1个存储库加载,然后尝试将其保存在另一个存储库(attach/detach/setobjectstate)中,则可能会遇到大问题。 – Gats 2012-03-15 06:00:05

2

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

....当我在分批过程,由此多个 线程与简单 ObjectContext的存储沿着访问资源库使用该存储库中,我得到的例外,因为一个ObjectContext的不能 被共享(EF是通过本身由于这个原因,不是线程安全的)。因此, 对SimpleObjectContextStorage进行了很小的修改,现在看起来也是 :我只是简单地将存储变量threadstatic 并在其他方法中使用该属性(_storage是 每个线程都重复,但只填充为第一个线程通过 静态构造函数调用)[ThreadStatic] private static Dictionary _storage;

private static Dictionary Storage {get {return _storage ?? (_storage = new Dictionary()); }}注意:ThreadStatic预计相应的变量是静态的为好,但不 因为你通常通过ObjectContextManager.Init呼叫定义每个应用程序只有一个 存储,这应该有一定影响。