我有一个应用程序,它为每个不同的项目执行RESTful API的几个后续HTTP请求。
我必须处理执行这些请求的异常的代码类似于Concurrency in C# Cookbook Stephen Cleary中描述的代码,方法2.4:
var tasks = new List<Task>();
foreach(var item in items)
{
tasks.Add(ProcessItemAsync(item));
}
var parentTask = Task.WhenAll(tasks);
try {
await parentTask;
} catch {
var exceptions = parentTask.Exception;
if (exceptions != null) {
// log individual exceptions
}
}
在分析日志时,我注意到某些处理没有导致发送所有需要的请求。但是,日志中没有记录任何例外情况。
调试应用程序时,我发现调用其中一个端点导致由于Web API超时而抛出TaskCanceledException。但是,parentTask.Exception
属性为null
,因此,我没有在日志中正确记录此异常。
我的问题如下:
答案 0 :(得分:5)
您可以通过阅读有关任务取消的this documentation来获取有关此内容的更多信息,尤其是此部分:
如果您正在等待转换到已取消状态的任务,a System.Threading.Tasks.TaskCanceledException异常(包装在 抛出AggregateException异常)。注意这个例外 表示取消成功而不是错误的情况。 因此,任务的异常属性返回null 。
所以重点是 - 任务取消是一个预期的事情,它不是一个错误。因此没有理由设置Exception
属性 - 有关取消的信息已记录在Task
状态。
另一个故事是超时 是一个错误,不应导致任务取消。另一方面,待处理的网页请求 在一段时间后(超时后)被取消,因此可以辩解。
作为一种变通方法,您可以检查tasks
数组中的所有任务,看看它们是否处于取消状态(IsCancelled
返回true)并相应地记录。
答案 1 :(得分:2)
TaskCanceledException由Task专门处理。
在Task中未处理TaskCanceledException时。它只是将任务中的IsCanceled属性设置为true。
注意,如果等待Task将抛出TaskCanceledException异常,而Task.Exception将保持为null。
答案 2 :(得分:2)
虽然可能处理汇总异常,但我认为 clean 可以单独处理它们:
var tasks = new List<Task>();
foreach(var item in items)
tasks.Add(ProcessItemAndLogExceptionsAsync(item));
await Task.WhenAll(tasks);
private static async Task ProcessItemAndLogExceptionsAsync(Item item)
{
try
{
await ProcessItemAsync(item);
}
catch (Exception ex)
{
// Log exception
}
}
通过这种方式,您也可以获得OperationCanceledException
。