当有一个或两个任务时,它可以正常工作,但当我们列出多个任务时,会抛出错误“任务已取消”。
List<Task> allTasks = new List<Task>();
allTasks.Add(....);
allTasks.Add(....);
Task.WaitAll(allTasks.ToArray(), configuration.CancellationToken);
private static Task<T> HttpClientSendAsync<T>(string url, object data, HttpMethod method, string contentType, CancellationToken token)
{
HttpRequestMessage httpRequestMessage = new HttpRequestMessage(method, url);
HttpClient httpClient = new HttpClient();
httpClient.Timeout = new TimeSpan(Constants.TimeOut);
if (data != null)
{
byte[] byteArray = Encoding.ASCII.GetBytes(Helper.ToJSON(data));
MemoryStream memoryStream = new MemoryStream(byteArray);
httpRequestMessage.Content = new StringContent(new StreamReader(memoryStream).ReadToEnd(), Encoding.UTF8, contentType);
}
return httpClient.SendAsync(httpRequestMessage).ContinueWith(task =>
{
var response = task.Result;
return response.Content.ReadAsStringAsync().ContinueWith(stringTask =>
{
var json = stringTask.Result;
return Helper.FromJSON<T>(json);
});
}).Unwrap();
}
抛出TaskCanceledException有2个可能的原因:
在任务完成之前,与取消令牌关联的CancellationTokenSource上的Cancel()。
请求超时,即没有在您在HttpClient.Timeout中指定的时间范围内完成。
我猜是暂停了。(如果它是一个明确的消去,你可能已经知道了。)你可以通过检查异常来确定:
try
{
var response = task.Result;
}
catch (TaskCanceledException ex)
{
// Check ex.CancellationToken.IsCancellationRequested here.
// If false, it's pretty safe to assume it was a timeout.
}
在我的。net核心3.1应用程序中,我得到了两个问题,其中内部原因是超时异常。
一是我得到了聚合异常在它的内部异常是超时异常
2、其他情况为任务取消例外
我的解决方案是
catch (Exception ex)
{
if (ex.InnerException is TimeoutException)
{
ex = ex.InnerException;
}
else if (ex is TaskCanceledException)
{
if ((ex as TaskCanceledException).CancellationToken == null || (ex as TaskCanceledException).CancellationToken.IsCancellationRequested == false)
{
ex = new TimeoutException("Timeout occurred");
}
}
Logger.Fatal(string.Format("Exception at calling {0} :{1}", url, ex.Message), ex);
}
我使用了一个简单的调用,而不是异步。当我添加等待和使方法异步开始工作良好。
public async Task<T> ExecuteScalarAsync<T>(string query, object parameter = null, CommandType commandType = CommandType.Text) where T : IConvertible
{
using (IDbConnection db = new SqlConnection(_con))
{
return await db.ExecuteScalarAsync<T>(query, parameter, null, null, commandType);
}
}
推广@JobaDiniz的评论来回答:
不要做显而易见的事情,释放HttpClient实例,即使代码“看起来是正确的”:
async Task<HttpResponseMessage> Method() {
using (var client = new HttpClient())
return client.GetAsync(request);
}
丢弃HttpClient实例会导致其他HttpClient实例启动的HTTP请求被取消!
c#的新RIAA语法也是如此;稍微不那么明显:
async Task<HttpResponseMessage> Method() {
using var client = new HttpClient();
return client.GetAsync(request);
}
相反,正确的方法是为你的应用程序或库缓存一个静态HttpClient实例,并重用它:
static HttpClient client = new HttpClient();
async Task<HttpResponseMessage> Method() {
return client.GetAsync(request);
}
Async()请求方法都是线程安全的。