2015-12-08 59 views
0

我有一個試圖利用一些async代碼的WebForms項目工作正常。在早期發育過程,我只是要求我在Page_Loadasync代碼(這也是async),並將結果寫入Response。很好,很容易進行測試。這一切都按預期工作。異步功能死鎖,但如果調用在Page_Load中

的代碼可以總結爲:

  1. 獲取Azure的授權令牌。
  2. 朝着Azure的REST API的HTTP請求。
  3. 將結果返回給客戶端。

我很驚訝,因此,當我試圖在WebMethod內調用這個async方法時,它失敗了。它似乎在其他async代碼(特別是Azure AD AuthenticationContext.AcquireTokenAsync方法)上發生了死鎖。

我首先想到的是一些背景巫術,但ConfigureAwait(false)沒有任何效果。所以我對於什麼是不同的而感到茫然。我試過WebMethodasync或者沒有結果差異。快速測試顯示,有什麼錯WebMethod是如何配置的 - 有我的代碼返回初以來它的工作如預期(達到調用廣告代碼之前)。雖然沒有什麼異步的事情發生。

我也使用用於獲取天青AD令牌非異步方法嘗試。這工作正常,但是當我的應用程序試圖發出HTTP請求時(使用RestSharp.Portable庫,它僅提供async方法),它會卡住。我的代碼有看起來像:

protected async Task<JObject> PerformRequest(string path, Method method, string apiVersion, string requestBody) 
{ 
    RestClient client = new RestClient("https://management.azure.com"); 
    RestRequest request = new RestRequest(path, method); 
    request.AddParameter("api-version", apiVersion); 
    request.AddHeader("Authorization", await this.GetAccessTokenAsync()); 
    IRestResponse<JObject> response = await client.Execute<JObject>(request); 
    return response.Data; 
} 

,我的工作Page_Load和使用非工作WebMethod幾乎完全相同,不同之處在於WebMethod返回結果,而Page_Load寫結果到Response的代碼。

GetAccessToken樣子:

public async Task<string> GetAccessTokenAsync() 
{ 
    string tenantId = "xxx"; 
    AuthenticationContext authenticationContext = new AuthenticationContext($"https://login.windows.net/{tenantId}"); 
    ClientCredential credential = new ClientCredential(clientId: "xxx", clientSecret: "xxx="); 
    AuthenticationResult result = await authenticationContext.AcquireTokenAsync(resource: "https://management.core.windows.net/", clientCredential: credential); 

    if (result == null) throw new InvalidOperationException("Failed to obtain the JWT token"); 

    return this.accessToken = result.AccessTokenType + " " + result.AccessToken; 
} 

這一切的呼叫會在WebMethod直接發(作爲唯一的WebMethod目前所做的):

return await this.PerformRequest("xxx", Method.GET, "xxx", null).ContinueWith(result => result.ToString()); 

爲什麼我的應用程序是在WebMethod中調用此代碼時出現此問題,但在Page_Load中沒有此問題?我能做些什麼來解決這個問題?

+1

我們可以看到你調用'PerformRequest'的地方嗎?你在任何地方等待'PerformRequest'調用的結果嗎? – spender

+0

你可以將代碼發佈到this.GetAccessToken嗎? – Aron

+0

另外,請你可以發佈運行此代碼的結果與HTTP嗅探器,如提琴手。 – Aron

回答

0

更改

IRestResponse<JObject> response = await client.Execute<JObject>(request); 

IRestResponse<JObject> response = await client.Execute<JObject>(request).ConfigureAwait(false); 

這是否幫助你嗎? 問題在於兩個「await」都在等待同時捕獲相同的上下文,ConfigureWait阻止了這個(請閱讀它的文檔)

+0

聽起來就像你在暗示兩個內部任務是同時運行的。但我認爲它應該按順序運行,不應該「同時」發生。 – Aron

+0

請注意,異步/等待模式是一個陷阱http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html –

+0

是的。但這是與Task.Result交互導致的問題。 OP正在運行「完全異步」。 – Aron