2012-12-10 27 views
3

我們最近開發了一個新的ASP.NET MVC 4 web應用程序(C#/ Visual Studio)。經過本地測試和調試後,我們將其部署到生產環境中,然後開始獲得越來越多的健康監測郵件。這些具有不同的異常消息:關於併發使用MVC應用程序的堆棧空問題

  • 堆棧爲空。
  • 收藏已修改;枚舉操作可能不會執行。
  • 項目已被添加。鍵入詞典:添加'ALL_HTTP'鍵:'ALL_HTTP'(其他鍵也提到)。
  • 價值不符合預期範圍。

例如,我們無法簡單地解決或重現一系列錯誤類型。 「空棧」是最常發生的一次,每天發生幾次100次(例如1-10%的用戶),因此我們將重點放在這一次,因爲其他錯誤似乎相關。這是一個部分堆棧跟蹤:

Exception information: 
Exception type: System.InvalidOperationException 
Exception message: Stack empty. 
... 
Stack trace: at System.ThrowHelper.ThrowInvalidOperationException(ExceptionResource resource) 
at System.Collections.Generic.Stack`1.Pop() 
at System.Web.WebPages.TemplateStack.Pop(HttpContextBase httpContext) 

如圖所示堆棧跟蹤大多完全位於MVC框架(System.Web)中。我們自己的代碼中唯一出現在某些堆棧跟蹤中的代碼位於請求的URL的視圖(.cshtml文件)中,然後在@ Html.RenderAction()調用中。到目前爲止,我們已經將很多這些重構到RenderPartial()調用中。這會導致堆棧跟蹤中看不到更多視圖,儘管某些RenderPartial現在也提供了一些

搜索此錯誤指示併發/並行執行是原因。這與我們最初無法在本地重現錯誤的事實相符,但它確實發生在生產上。我們沒有進行負載測試,但現在已經能夠通過同時啓動大量應用程序/請求,在本地開發者系統上重現錯誤。然而,在我們的代碼中,沒有任何操作是通過顯式並行指令完成的

這似乎與MVC視圖的線程安全無關。但很難想象沒有其他人會遇到這種情況。我們每天有幾千名訪問者,在任何時候大約有30多名活躍用戶。可悲的是,這個數字正在下降,因爲谷歌排名下降(與這個問題有關)。

有沒有人知道這個問題的解決方案?

+1

你是否將模型中的任何可能被多線程訪問的對象作爲模型傳遞?就像一個共享對象? – vtortola

+0

vtorola不是真的! Wel所有模型都從具有靜態數據庫上下文對象的BaseModel進行擴展,但是這存儲在HTTPContext(使用鍵)中。這樣做是爲了在'每個請求'的基礎上使用它(它在第一次訪問時被延遲加載)。 堆棧跟蹤不指向此代碼,它們只在視圖邏輯中。此外,我以前已經在代碼中添加了一個'鎖'語句,以便以防萬一。這似乎沒有改變任何東西。 我們正在使用實體框架。 – Bart

+0

令人毛骨悚然的Woa:D您應該使用您的DbContext作爲控制器的一部分,從數據庫生成所需的POCO對象,然後創建視圖模型。一個視圖應該是線程安全的,我從來沒有見過這樣的錯誤,所以我建議開始深入地看看令人毛骨悚然的共享DbContext。也許堆棧跟蹤並不指向那個BaseModel對象,但絕對是它的一部分被多個線程共享。 – vtortola

回答

3

我正在開發一個ASP.NET MVC 4應用程序,我也遇到了你提到的錯誤。儘管它們不同,但它們似乎具有相同的來源。花了幾個小時試圖找出原因(以及很多代碼更改)之後,我開始從頭開始分析。

因爲我使用的是自定義路由,並且有一個處理該路由的數據庫訪問權限,該處理程序檢查了幾件事情並訪問數據庫。非常快速地打開多個瀏覽器選項卡(使用IISExpress> Show All Application窗口或通過Ctrl + Click鏈接)我很高興地看到所有頁面都顯示正確,而不是幾個隨機錯誤消息。嘗試了幾次以確定並確定在訪問數據庫時出現了問題。

public class MyNewRouteHandler : IRouteHandler { 

    IHttpHandler MvcHandler; 

    public IHttpHandler GetHttpHandler(RequestContext requestContext) { 
     MvcHandler = new MvcHandler(requestContext); 

     // some checkings and 
     // some database access code 
     // that was commented 

     return MvcHandler; 
    } 
} 

一位同事建議我增加了一個小的線程睡眠該方法中:GetHttpHandler。該行使錯誤再次出現,表明問題與DB無關......當我這樣做時,我發現MvcHandler對象被定義爲一個類屬性,並且可能是一個似乎是併發問題的來源(只有當多個幾乎連續的訪問被執行時,問題才顯示出來)。將MvcHandler對象移至方法內的本地對象。

public class MyNewRouteHandler : IRouteHandler { 

    public IHttpHandler GetHttpHandler(RequestContext requestContext) { 
     IHttpHandler MvcHandler = new MvcHandler(requestContext); 

     // some checkings and 
     // some database access code 
     // that was commented 

     return MvcHandler; 
    } 
} 

而經過測試,沒有更多的錯誤。取消註釋了所有訪問數據庫的代碼(並執行了其他檢查),但仍未發現更多錯誤。差不多3天過去了,一切仍然正常。

+0

偉大的nrod!事實上,我正在看它,但似乎也使用自定義的MVC HttpHandler。而這些傢伙似乎並不是線程安全的......因爲堆棧跟蹤根本沒有指向路由,所以很難找到。 – Bart

0

這種做Custom Route Handler的方法確實解決了我的大多數我的錯誤,但我仍然有一些左和新的消息。其中一人指向我的Custom Route Handler中的代碼行,他們都有共同的事實,即一個字典正在被MVC框架處理,所以......我是否還有一個併發問題?

我是這麼認爲的,我所有的方法屬性都在public IHttpHandler GetHttpHandler(RequestContext requestContext)方法中移動,不僅僅是前面提到的方法。其中之一是RouteData集合...最後和2天后似乎沒有更多的錯誤顯示。