HttpClient in using 语句导致任务取消
HttpClient in using statement causes Task cancelled
我为我的 api 调用创建了一个 FileResult : IHttpActionResult
webapi return 类型。 FileResult 从另一个 url 下载文件,然后 return 将流传输到客户端。
最初我的代码有如下 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,则任务的状态将更改为已取消。但是,由于我在 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)
{...}
}
知道使用导致问题的原因吗?
我对任务取消异常有类似的问题。如果您尝试捕获 AggregateException
或在您的 WebException
下方设置捕获所有 Exception
块,您很可能会发现您捕获了它,但有一个例外,条目为 "A task was canceled"
我做了一些调查,发现 AggregateException
像各种线程中描述的那样具有误导性;
Bug in httpclientgetasync should throw webexception not taskcanceledexception
我最终更改了我的代码以设置明确的超时(其中 asyncTimeoutInMins
是从 app.config 文件中读取的);
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;
I know that if the HttpClient is disposed before the asychronous call is finished the Task's state will change to canceled. 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.
但是该任务 做什么? 它获取流。因此,您的代码以 Stream
结束,当它关闭 HttpClient
.
时,它可能会或可能不会被完全读取
HttpClient
专为重用(和同时使用)而设计,因此我建议完全删除 using
并将 HttpClient
声明移动到 static
class 成员。但是如果你想关闭并重新打开客户端,你应该能够通过在关闭 HttpClient
.
之前 将流完全读入 到内存中来使其工作
我为我的 api 调用创建了一个 FileResult : IHttpActionResult
webapi return 类型。 FileResult 从另一个 url 下载文件,然后 return 将流传输到客户端。
最初我的代码有如下 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,则任务的状态将更改为已取消。但是,由于我在 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)
{...}
}
知道使用导致问题的原因吗?
我对任务取消异常有类似的问题。如果您尝试捕获 AggregateException
或在您的 WebException
下方设置捕获所有 Exception
块,您很可能会发现您捕获了它,但有一个例外,条目为 "A task was canceled"
我做了一些调查,发现 AggregateException
像各种线程中描述的那样具有误导性;
Bug in httpclientgetasync should throw webexception not taskcanceledexception
我最终更改了我的代码以设置明确的超时(其中 asyncTimeoutInMins
是从 app.config 文件中读取的);
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;
I know that if the HttpClient is disposed before the asychronous call is finished the Task's state will change to canceled. 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.
但是该任务 做什么? 它获取流。因此,您的代码以 Stream
结束,当它关闭 HttpClient
.
HttpClient
专为重用(和同时使用)而设计,因此我建议完全删除 using
并将 HttpClient
声明移动到 static
class 成员。但是如果你想关闭并重新打开客户端,你应该能够通过在关闭 HttpClient
.