[英]HttpClient in using statement causes Task cancelled
I created a FileResult : IHttpActionResult
webapi return type for my api calls. 我为我的api调用创建了一个FileResult : IHttpActionResult
webapi返回类型。 The FileResult downloads a file from another url and then returns the stream to the client. FileResult从另一个URL下载文件,然后将流返回给客户端。
Initially my code had a using
statement like below: 最初我的代码有一个如下所示的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)
{...}
}
However this would intermittently cause a TaskCanceledException
. 但是,这会间歇性地导致TaskCanceledException
。 I know that if the HttpClient is disposed before the asychronous call is finished the Task's state will change to canceled. 我知道如果在异步调用完成之前处理了HttpClient,Task的状态将变为取消。 However since I use an await in: Content = new System.Net.Http.StreamContent(await httpClient.GetStreamAsync(this.filePath))
that should prevent the HttpClient from being disposed off in the middle of the task completion. 但是因为我使用了await : Content = new System.Net.Http.StreamContent(await httpClient.GetStreamAsync(this.filePath))
,它应该阻止HttpClient在任务完成过程中被处理掉。
Why does that task get canceled? 为什么该任务被取消? It is not because of a timeout since this has happened on the smallest requests and doesn't always occur on large requests. 这不是因为超时,因为这发生在最小的请求上,并不总是发生在大请求上。
When I removed the using
statement the code worked properly: 当我删除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)
{...}
}
Any idea why the using caused the issue? 知道为什么使用导致了这个问题吗?
I know that if the HttpClient is disposed before the asychronous call is finished the Task's state will change to canceled. 我知道如果在异步调用完成之前处理了HttpClient,Task的状态将变为取消。 However since I use an await in: Content = new System.Net.Http.StreamContent(await httpClient.GetStreamAsync(this.filePath)) that should prevent the HttpClient from being disposed off in the middle of the task completion. 但是因为我使用了await:Content = new System.Net.Http.StreamContent(等待httpClient.GetStreamAsync(this.filePath)),它应该阻止HttpClient在任务完成过程中被处理掉。
But what does that task do? 但是这项任务做了什么? It gets the stream. 它得到了流。 So, your code ends up with a Stream
that may or may not be completely read when it closes the HttpClient
. 因此,您的代码最终会得到一个Stream
,当它关闭HttpClient
时可能会或可能不会被完全读取。
HttpClient
is specifically designed for reuse (and simultaneous use), so I recommend removing the using
completely and moving the HttpClient
declaration to a static
class member. HttpClient
专门用于重用(和同时使用),因此我建议完全删除using
并将HttpClient
声明移动到static
类成员。 But if you want to close and reopen the clients, you should be able to get it working by reading the stream entirely into memory before closing the HttpClient
. 但是,如果要关闭并重新打开客户端,则应该能够通过在关闭HttpClient
之前将流完全读入内存来使其工作。
I had a similar issue with Task Canceled exceptions. 我遇到了类似于Task Canceled异常的问题。 If you try catching AggregateException
or having a catch all Exception
block underneath your WebException
, you may well find that you catch it, with one exception with the entry stating "A task was canceled" 如果您尝试捕获AggregateException
或在WebException
下面捕获所有Exception
块,您可能会发现它捕获它,但有一个例外,条目说明“任务已被取消”
I did some investigation and found that the AggregateException
is quite misleading as described in various threads; 我做了一些调查,发现AggregateException
很容易产生误导,如各种线程所述;
Setting HttpClient to a too short timeout crashes process 将HttpClient设置为太短的超时会导致进程崩溃
How can I tell when HttpClient has timed out? 如何判断HttpClient何时超时?
Bug in httpclientgetasync should throw webexception not taskcanceledexception httpclientgetasync中的错误应该抛出webexception而不是taskcanceledexception
I ended up changing my code to set an explicit timeout (where asyncTimeoutInMins
is read from the app.config file); 我最终更改了我的代码以设置显式超时(从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.