2015-11-20 62 views
1

編輯:我現在通過簡單地將按鈕點擊處理程序標記爲async void並等待任務來解決問題。我認爲WebForms無法以任何方式處理異步,除非與RegisterAsyncTask一起使用。雖然這解決了我的問題,但我仍然對代碼處於死鎖之下的原因感興趣,因爲它違背了我對當前C#代碼異步工作的理解,所以仍然讚賞答案。ASP.NET死鎖儘管ConfigureAwait(false)

我有一個服務公開了一個異步方法,它向一些api發送一個請求。此方法在webforms代碼隱藏中消耗。我知道ASP.NET只允許一次執行一個線程,因此調用Task.Wait()會導致死鎖,因爲等待處理的任務在上下文線程被阻止時無法在完成時恢復執行。

但是,我的理解(從讀this blog),在等待的任務上調用ConfigureAwait(false)會導致任務在線程池線程上運行,因此可以恢復上下文線程上的執行。儘管如此,我仍然遇到了來自下面代碼的僵局。爲什麼是這樣?

protected void Activate(object sender, CommandEventArgs e) 
{ 
    var someID = int.Parse((string) e.CommandArgument); 
    DoAsyncThingWithID(someID).Wait(); 
} 

private async Task DoAsyncThingWithID(int ID) 
{ 
    try 
    { 
     await new SomeService() 
      .DoSomeAsyncWork(ID) 
      .ConfigureAwait(false); 
    } 
    catch (AppropriateException e) 
    { 
     DealWithIt(); 
    } 
} 

值得注意的是:DoSomeAsyncWork(int)在它下面有更多的異步方法。在底部有一個API包裝對象(負責發送HTTP請求)的方法不是異步,但調用Task.Run(() => api.SendThingy());

這可能是問題嗎?

+0

發佈你的搜索答案並收聽。 –

回答

5

但是,由於它是我的理解(從閱讀這個博客),其對期待已久的任務調用ConfigureAwait(假)將導致任務上的線程池線程,而不是運行,因此執行上下文線程可以恢復。

其實用ConfigureAwait(false)延續不關心它在執行什麼情況下目前的方法 - 與絕大多數的時間,這意味着它會繼續一個線程池線程。

因此,DoSomeAsyncWork仍然會在ASP.NET上下文中運行。出於這個原因,只有一個ConfigureAwait(false)是不夠的。您必須確保DoSomeAsyncWork也使用ConfigureAwait(false)以及它調用的所有異步方法以及它們調用的所有異步方法等,包括Microsoft或第三方庫方法。

這就是爲什麼我建議不要阻止開始。如果你絕對有到,ConfigureAwait(false)黑客只是試圖繞過它的其中一種方法。

+0

我明白了,是的,這確實使得依靠下面所有人調用該方法都是非常不可取的。我想你可以讓它成爲你的團隊的標準,但是你仍然無法在第三方庫中強制執行它。幸運的是,他們實際上在webforms中實現了一些異步支持,因爲我們有一些遺留項目在其中。 – kai

0

我現在只需將按鈕點擊處理程序標記爲async void並等待任務即可解決問題。我認爲WebForms不能以任何方式處理async,除非與RegisterAsyncTask一起使用。雖然這解決了我的問題,但我仍然對原始代碼爲什麼死鎖感興趣,因爲它違背了我當前對異步C#代碼工作方式的理解,因此還有進一步的答案。