![](/img/trans.png)
[英]HttpClient.PostAsJsonAsync throws TaskCanceledException
[英]HttpClient.PostAsJsonAsync never sees when the post is succeeding and responding
我們正在使用HttpClient將json發布到一個寧靜的Web服務。 在一個例子中,我們遇到了困擾我們的事情。 使用postman,fiddler等工具,我們可以發布到端點並看到它正在工作。 當我們對HttpClient.PostAsJsonAsync做同樣的事情時,我們可以在我們發布的軟件中驗證它收到的數據就好了。 但是,我們的PostAsJsonAsync最終會超時,而不是給我們一個響應。
我們與創建我們正在消費的服務的團隊合作,加上我們的額外測試,我們還沒有真正超時的服務。
每次我們使用HttpClient發布帖子時,我們都可以驗證我們發布的目標軟件是否確實獲得了數據。 每當我們從任何其他工具發布到目標軟件的帖子時,我們總是很快看到狀態代碼為200的響應。關於HttpClient的某些內容未能接受來自此特定服務的響應。 有沒有人知道我們可以從這里看到什么?
這是代碼(雖然它是如此千篇一律,我幾乎覺得不需要)
public string PostData(string resourcePath, Object o, Boolean isCompleteUrl = false, int timeoutMinutes = -1)
{
using (var client = new HttpClient())
{
if (timeoutMinutes > 0)
{
client.Timeout = new TimeSpan(0,timeoutMinutes,0);
}
var useUrl = isCompleteUrl ? resourcePath : ApiBase + resourcePath;
var response = client.PostAsJsonAsync(useUrl, o).Result;
if(response.StatusCode == System.Net.HttpStatusCode.OK)
{
return response.Content.ReadAsStringAsync().Result;
}
return "";
}
}
這個:
var response = client.PostAsJsonAsync(useUrl, o).Result;
導致代碼死鎖。 在阻止異步API的情況下通常會出現這種情況,這就是為什么你會遇到“我看不到任何響應”的原因 。
這怎么會造成僵局? 您在包含同步上下文的環境中執行此請求的事實,可能是屬於UI的同步上下文。 它正在執行異步請求,當響應到達時,它會繼續通過IO完成線程,該線程嘗試將延續發布到同一UI上下文中,該上下文當前被.Result
調用阻止。
如果要同步發出HTTP請求,請改用WebClient
。 如果要正確利用異步API,則await
而不是使用.Result
進行阻止。
我有同樣的問題, 這個SO答案為我解決了。
簡而言之,您必須使用ConfigureAwait(false)
擴展來避免死鎖:
var response = await client.PostAsJsonAsync(useUrl, o).ConfigureAwait(false);
您有沒有理由不遵循異步等待模式? 你正在調用異步方法,但不是在等待它。 您沒有說調用您的REST服務的代碼是Windows窗體還是ASP.NET應用程序,但是.Result
可能會導致您遇到問題 。
你可以像這樣重構你的方法:
public async Task<string> PostData(string resourcePath, Object o, Boolean isCompleteUrl = false, int timeoutMinutes = -1)
{
using (var client = new HttpClient())
{
if (timeoutMinutes > 0)
{
client.Timeout = new TimeSpan(0,timeoutMinutes,0);
}
var useUrl = isCompleteUrl ? resourcePath : ApiBase + resourcePath;
var response = await client.PostAsJsonAsync(useUrl, o);
if(response.StatusCode == System.Net.HttpStatusCode.OK)
{
return await response.Content.ReadAsStringAsync();
}
return "";
}
}
這是對@Justin Helgerson解決方案的略微修改。 您的方法中有2個阻止.Result
調用; 一旦你去異步,你應該修復它們。
public async Task<string> PostDataAsync(string resourcePath, Object o, Boolean isCompleteUrl = false, int timeoutMinutes = -1)
{
using (var client = new HttpClient())
{
if (timeoutMinutes > 0)
{
client.Timeout = new TimeSpan(0,timeoutMinutes,0);
}
var useUrl = isCompleteUrl ? resourcePath : ApiBase + resourcePath;
var response = await client.PostAsJsonAsync(useUrl, o);
if(response.StatusCode == System.Net.HttpStatusCode.OK)
{
return await response.Content.ReadAsStringAsync();
}
return "";
}
}
注意我還根據TAP模式將方法重命名為PostDataAsync
。
System.Net.ServicePointManager.Expect100Continue = false;
我們案例中的一行代碼解決了這個問題。 來自不同團隊的開發人員提供了該建議,並且可行。 我還沒有去谷歌,並閱讀它足以提供解釋的內容。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.