2013-04-22 69 views
3

我正在寫一些MVC4異步控制器代碼,並且遇到了一個問題,因此我會向兩個長時間運行的Web服務異步調用,而第二個調用看起來是在錯誤的線程中。在多個等待場景中的HTTPContext

這裏是代碼片段:

public async Task<ActionResult> AmendDetails(Model model) 
{ 
    ClientMaintenanceClient clientService = new ClientMaintenanceClient(); 
    UpdateResponse clientResponse = await clientService.GetForUpdateAsync(clientService.CreateRequest(model.Id)); 

    StaticDataEnquiryClient staticService = new StaticDataEnquiryClient(); 
    DataResponse staticResponse = await staticService.GetPayMethodsAsync(staticService.CreateRequest()); 

    ... 
} 

實質上,要的createRequest()的調用將查找會話標識出的HttpContext,並創建一個呼叫中使用該服務所形成的WCF請求對象。

然而在執行時,第一個調用很好,但第二個異步調用失敗,因爲HttpContext爲null,這會導致我相信我現在處於不同的線程。

當我在MVC3和.Net4.5之前完成此操作時,必須通過AsyncManager(使用EAP)從異步調用中返回時手動同步線程,但我認爲我不再需要這樣做TAP。

如果我並行執行代碼,使用下面的代碼片段,問題就會消失。

public async Task<ActionResult> AmendDetails(Model model) 
{ 
    ClientMaintenanceClient clientService = new ClientMaintenanceClient(); 
    var clientTask = clientService.GetForUpdateAsync(clientService.CreateRequest(model.Id)); 

    StaticDataEnquiryClient staticService = new StaticDataEnquiryClient(); 
    var staticTask = staticService.GetPayMethodsAsync(staticService.CreateRequest()); 

    await Task.WhenAll(clientTask,staticTask); 
    UpdateResponse clientResponse = await clientTask; 
    DataResponse staticResponse = await StaticTask; 
    ... 
} 
  • 我假設的是,在第一個片段,第一個是AWAIT過程的時候我到了第二的await移動到後臺線程,等於是,我仍然在後臺線程。 HttpContext將爲空,因爲我無法從該線程獲得它。

  • 我還假設在第二段代碼中,我在第一次等待之前做了所有的HTTPContext查找,所以我從來沒有將HTTPContext看作null,因爲我從不從後臺線程調用它。

任何人都可以證實我的上述假設?我不想在我的代碼中看到一個明顯的錯誤,它會在以後回來並咬我!

更新:

我決定在這裏檢查執行過程中的線程,它出現第二的await確實在不同的線程比第一的await發生。有趣的是,在第二次調用時,看起來HttpContext不爲空。它是空的HttpContext.Current

我通過訪問會話ID:

HttpContext.Current.Session.SessionId 

我猜我需要第二的await在什麼地方同步的東西,但我不知道是什麼。

+0

在ASP.NET中,線程不喜歡GUI應用程序。你的第二個調用應該在正確的上下文中執行,同時設置HttpContext。 (換句話說,我不知道你的代碼有什麼問題。) – svick 2013-04-22 16:53:48

回答

4

你的代碼一定是應該工作。自從你提到MVC 3以來,我假設這是一個升級項目。在這種情況下,請確保你在你的web.config以下:

<appSettings> 
    <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" /> 
</appSettings> 
+0

嗯...是的工作。它做了什麼?MSDN陳述道:「爲啓用WebSocket的應用程序設置此兼容性開關是必需的,在Web窗體頁面中使用基於任務的異步,以及對於某些其他異步行爲。」這是否是某些其他異步行爲? – Nick 2013-04-22 17:11:09

+0

說實話,我並不是100%確定爲什麼你的代碼在新的(任務友好的)'AspNetSynchronizationContext'和舊的'LegacyAspNetSynchronziationContext'之間工作不同。我懷疑,與傳統的,它是太早完成請求 - 但我會認爲'異步'MVC控制器會阻止... – 2013-04-22 17:38:40