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呼叫定義每個應用程序只有一個 存儲,這應該有一定影響。