ASP.NET web API - System.Threading.Tasks.TaskCanceledException: 一个任务被取消的困境
ASP.NET web API - System.Threading.Tasks.TaskCanceledException: A task was canceled dilemma
我有一个 asp.net 网站 API。 (net framework 4.6.1) 我在我的一项操作中调用了第三方 rest API (Product)。在功能测试中,一切都按预期工作,没问题。但是当我进行尖峰测试时(比方说,100 个用户,10 秒的启动时间),在一些成功的响应之后我得到 System.Threading.Tasks.TaskCanceledException: A task was canceled error
。我用谷歌搜索并发现这可能是由于超时。我添加了 TimeSpan.FromSeconds(600);
但仍然出现相同的错误。
我是这样称呼这个第 3 方的 API。异步调用有什么问题吗?你能看看我的代码吗?
public class UtilitiesTest
{
private static readonly HttpClient _httpClient = new HttpClient();
//some not relevant code here
public static async Task<HttpResponseMessage> CallRazer(GameRequest gameRequest, string url)
{
try
{
FormUrlEncodedContent content = null;
if (url == "Product/")
{
try
{
//some code here
//Timeout
_httpClient.Timeout = TimeSpan.FromSeconds(600);
//Call Game
var response = await _httpClient.PostAsync("https://test.com/" + url, content);
return response;
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
finally
{
content.Dispose();
}
}
else
{
try
{
//some code here
//Call Game
var response = await _httpClient.PostAsync("https://test.com/" + url, content);
return response;
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
finally
{
content.Dispose();
}
}
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
}
}
我是这样称呼 Razer 的:
private async Task<HttpResponseMessage> CallProducts()
{
//some code here
#region Call Razer for products
//**Call Razer**
var response = await Utilities.CallRazer(products, "Product/");
var htmlResponse = await response.Content.ReadAsStringAsync();
var model = JsonConvert.DeserializeObject<ProductResponseDto>(htmlResponse);
// some code here
return response;
}
另一个论坛有人建议我使用 HTTPWeb Request 而不是 Httpclient。所以我像下面这样更改了我的代码,所有的麻烦都消失了。
//HTTPWebRequest
var request = (HttpWebRequest) WebRequest.Create("http://test.com" + url);
request.ContentType = "application/x-www-form-urlencoded";
request.Method = "POST";
var keyValueContent = productRequest.ToKeyValue();
var formUrlEncodedContent = new FormUrlEncodedContent(keyValueContent);
var urlEncodedString = await formUrlEncodedContent.ReadAsStringAsync();
using (var streamWriter = new StreamWriter(await request.GetRequestStreamAsync()))
{
streamWriter.Write(urlEncodedString);
}
HttpWebResponse httpResponse = (HttpWebResponse) (await request.GetResponseAsync());
response = new HttpResponseMessage
{
StatusCode = httpResponse.StatusCode,
Content = new StreamContent(httpResponse.GetResponseStream()),
};
return response;
如果它在 600 秒后仍然超时,那么您的网络服务就跟不上了。
但是,是的,超时会产生一个TaskCanceledException
,这一点都不直观。这实际上至少在 .NET Core 中会发生变化 (just fixed last week),但这对您没有帮助。
这是我用来重新抛出 TimeoutException
的代码。 other 可能抛出 TaskCanceledException
的唯一原因是,如果您通过了最终被取消的 CancellationToken
,但您没有。所以肯定超时了。
} catch (TaskCanceledException) {
//Could have been caused by cancellation or timeout if you used one.
//If that was the case, rethrow.
//cancellationToken.ThrowIfCancellationRequested();
//HttpClient throws TaskCanceledException when the request times out. That's dumb.
//Throw TimeoutException instead and say how long we waited.
string time;
if (_httpClient.Timeout.TotalHours > 1) {
time = $"{_httpClient.Timeout.TotalHours:N1} hours";
} else if (_httpClient.Timeout.TotalMinutes > 1) {
time = $"{_httpClient.Timeout.TotalMinutes:N1} minutes";
} else if (_httpClient.Timeout.TotalSeconds > 1) {
time = $"{_httpClient.Timeout.TotalSeconds:N1} seconds";
} else {
time = $"{_httpClient.Timeout.TotalMilliseconds:N0} milliseconds";
}
throw new TimeoutException($"No response after waiting {time}.");
}
我有一个 asp.net 网站 API。 (net framework 4.6.1) 我在我的一项操作中调用了第三方 rest API (Product)。在功能测试中,一切都按预期工作,没问题。但是当我进行尖峰测试时(比方说,100 个用户,10 秒的启动时间),在一些成功的响应之后我得到 System.Threading.Tasks.TaskCanceledException: A task was canceled error
。我用谷歌搜索并发现这可能是由于超时。我添加了 TimeSpan.FromSeconds(600);
但仍然出现相同的错误。
我是这样称呼这个第 3 方的 API。异步调用有什么问题吗?你能看看我的代码吗?
public class UtilitiesTest
{
private static readonly HttpClient _httpClient = new HttpClient();
//some not relevant code here
public static async Task<HttpResponseMessage> CallRazer(GameRequest gameRequest, string url)
{
try
{
FormUrlEncodedContent content = null;
if (url == "Product/")
{
try
{
//some code here
//Timeout
_httpClient.Timeout = TimeSpan.FromSeconds(600);
//Call Game
var response = await _httpClient.PostAsync("https://test.com/" + url, content);
return response;
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
finally
{
content.Dispose();
}
}
else
{
try
{
//some code here
//Call Game
var response = await _httpClient.PostAsync("https://test.com/" + url, content);
return response;
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
finally
{
content.Dispose();
}
}
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
}
}
我是这样称呼 Razer 的:
private async Task<HttpResponseMessage> CallProducts()
{
//some code here
#region Call Razer for products
//**Call Razer**
var response = await Utilities.CallRazer(products, "Product/");
var htmlResponse = await response.Content.ReadAsStringAsync();
var model = JsonConvert.DeserializeObject<ProductResponseDto>(htmlResponse);
// some code here
return response;
}
另一个论坛有人建议我使用 HTTPWeb Request 而不是 Httpclient。所以我像下面这样更改了我的代码,所有的麻烦都消失了。
//HTTPWebRequest
var request = (HttpWebRequest) WebRequest.Create("http://test.com" + url);
request.ContentType = "application/x-www-form-urlencoded";
request.Method = "POST";
var keyValueContent = productRequest.ToKeyValue();
var formUrlEncodedContent = new FormUrlEncodedContent(keyValueContent);
var urlEncodedString = await formUrlEncodedContent.ReadAsStringAsync();
using (var streamWriter = new StreamWriter(await request.GetRequestStreamAsync()))
{
streamWriter.Write(urlEncodedString);
}
HttpWebResponse httpResponse = (HttpWebResponse) (await request.GetResponseAsync());
response = new HttpResponseMessage
{
StatusCode = httpResponse.StatusCode,
Content = new StreamContent(httpResponse.GetResponseStream()),
};
return response;
如果它在 600 秒后仍然超时,那么您的网络服务就跟不上了。
但是,是的,超时会产生一个TaskCanceledException
,这一点都不直观。这实际上至少在 .NET Core 中会发生变化 (just fixed last week),但这对您没有帮助。
这是我用来重新抛出 TimeoutException
的代码。 other 可能抛出 TaskCanceledException
的唯一原因是,如果您通过了最终被取消的 CancellationToken
,但您没有。所以肯定超时了。
} catch (TaskCanceledException) {
//Could have been caused by cancellation or timeout if you used one.
//If that was the case, rethrow.
//cancellationToken.ThrowIfCancellationRequested();
//HttpClient throws TaskCanceledException when the request times out. That's dumb.
//Throw TimeoutException instead and say how long we waited.
string time;
if (_httpClient.Timeout.TotalHours > 1) {
time = $"{_httpClient.Timeout.TotalHours:N1} hours";
} else if (_httpClient.Timeout.TotalMinutes > 1) {
time = $"{_httpClient.Timeout.TotalMinutes:N1} minutes";
} else if (_httpClient.Timeout.TotalSeconds > 1) {
time = $"{_httpClient.Timeout.TotalSeconds:N1} seconds";
} else {
time = $"{_httpClient.Timeout.TotalMilliseconds:N0} milliseconds";
}
throw new TimeoutException($"No response after waiting {time}.");
}