[英]HttpClient in using statement causes Task cancelled
我為我的api調用創建了一個FileResult : IHttpActionResult
webapi返回類型。 FileResult從另一個URL下載文件,然后將流返回給客戶端。
最初我的代碼有一個如下所示的using
語句:
public async Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
try
{
HttpResponseMessage response;
using (var httpClient = new HttpClient())
{
response = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new System.Net.Http.StreamContent(
await httpClient.GetStreamAsync(this.filePath))
};
}
return response;
}
catch (WebException exception)
{...}
}
但是,這會間歇性地導致TaskCanceledException
。 我知道如果在異步調用完成之前處理了HttpClient,Task的狀態將變為取消。 但是因為我使用了await : Content = new System.Net.Http.StreamContent(await httpClient.GetStreamAsync(this.filePath))
,它應該阻止HttpClient在任務完成過程中被處理掉。
為什么該任務被取消? 這不是因為超時,因為這發生在最小的請求上,並不總是發生在大請求上。
當我刪除using
語句時,代碼正常工作:
public async Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
try
{
HttpResponseMessage response;
var httpClient = new HttpClient();
response = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new System.Net.Http.StreamContent(
await httpClient.GetStreamAsync(this.filePath))
};
return response;
}
catch (WebException exception)
{...}
}
知道為什么使用導致了這個問題嗎?
我知道如果在異步調用完成之前處理了HttpClient,Task的狀態將變為取消。 但是因為我使用了await:Content = new System.Net.Http.StreamContent(等待httpClient.GetStreamAsync(this.filePath)),它應該阻止HttpClient在任務完成過程中被處理掉。
但是這項任務做了什么? 它得到了流。 因此,您的代碼最終會得到一個Stream
,當它關閉HttpClient
時可能會或可能不會被完全讀取。
HttpClient
專門用於重用(和同時使用),因此我建議完全刪除using
並將HttpClient
聲明移動到static
類成員。 但是,如果要關閉並重新打開客戶端,則應該能夠通過在關閉HttpClient
之前將流完全讀入內存來使其工作。
我遇到了類似於Task Canceled異常的問題。 如果您嘗試捕獲AggregateException
或在WebException
下面捕獲所有Exception
塊,您可能會發現它捕獲它,但有一個例外,條目說明“任務已被取消”
我做了一些調查,發現AggregateException
很容易產生誤導,如各種線程所述;
httpclientgetasync中的錯誤應該拋出webexception而不是taskcanceledexception
我最終更改了我的代碼以設置顯式超時(從app.config文件中讀取asyncTimeoutInMins
);
string jsonResponse = string.Empty;
try
{
using (HttpClient httpClient = new HttpClient())
{
httpClient.BaseAddress = new Uri(Properties.Settings.Default.MyWebService);
httpClient.DefaultRequestHeaders.Accept.Clear();
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
httpClient.Timeout = new TimeSpan(0, asyncTimeoutInMins, 0);
HttpResponseMessage response;
response = await httpClient.GetAsync("/myservice/resource");
// Check the response StatusCode
if (response.IsSuccessStatusCode)
{
// Read the content of the response into a string
jsonResponse = await response.Content.ReadAsStringAsync();
}
else if (response.StatusCode == HttpStatusCode.Forbidden)
{
jsonResponse = await response.Content.ReadAsStringAsync();
Logger.Instance.Warning(new HttpRequestException(string.Format("The response StatusCode was {0} - {1}", response.StatusCode.ToString(), jsonResponse)));
Environment.Exit((int)ExitCodes.Unauthorised);
}
else
{
jsonResponse = await response.Content.ReadAsStringAsync();
Logger.Instance.Warning(new HttpRequestException(string.Format("The response StatusCode was {0} - {1}", response.StatusCode.ToString(), jsonResponse)));
Environment.Exit((int)ExitCodes.ApplicationError);
}
}
}
catch (HttpRequestException reqEx)
{
Logger.Instance.Error(reqEx);
Console.WriteLine("HttpRequestException : {0}", reqEx.InnerException.Message);
Environment.Exit((int)ExitCodes.ApplicationError);
}
catch (Exception ex)
{
Logger.Instance.Error(ex);
throw;
}
return jsonResponse;
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.