每当任务在失败状态下运行到完成时,也就是说,当运行该任务的方法以某种方式失败时,它就会抛出AggregateException。
这是因为任务可以继续:
var t = SomeAsyncMethod().ContinueWith(a=> { });
如果SomeAsyncMethod抛出异常,ContinueWith也抛出异常,则聚合异常将具有该调用的所有异常。
然而,当您使用async/await调用并尝试/catch时,c#async state会展开聚合异常,并在代码中抛出原始异常。
代码中的问题与GetServerLog方法是同步的并且正在调用Task方法有关。
您可以:
var localClientManager = InitializeConnection();
var destinationPath = $"{ServerSecureLogFile}";
//Wait upto 120s
var cts = new CancellationTokenSource(TimeSpan.FromSeconds(120));
// assumes that this method will look at the token to stop processing and bubbling up a OperationCancelledException/TimeoutException if token expires.
// localClientManager can be null if InitializeConnection returns null or depends on other lazy/async initialization steps.
var result = ServerGetBasicSecureLogAsync(localClientManager, cts.Token);
var sw = Stopwatch.StartNew();
try
{
// This can cause deadlocks it Thread pool threads are waiting for a free thread and other locations are doing Waits: https://stackoverflow.com/questions/13140523/await-vs-task-wait-deadlock
//result.WaitOne(TimeSpan.FromSeconds(120));
result.GetAwaiter().GetResult();
}
catch(MySimpleException)
{
}
catch(OperationCancelledException)
{
}
finally
{
sw.Stop();
// could enclose cts in using statement
cts.Dispose();
}
因为GetAwaiter().GetResult()是异步状态调用的相同方法,所以它还展开聚合异常,通过使用try/catch,您也可以查看取消的操作。
此外,您不需要创建Task来运行异步方法:
async Task SomeAsyncMethod()
{
var localClientManager = InitializeConnection();
var destinationPath = $"{ServerSecureLogFile}";
//Wait upto 120s
var cts = new CancellationTokenSource(TimeSpan.FromSeconds(120));
// assumes that this method will look at the token to stop processing and bubbling up a OperationCancelledException/TimeoutException if token expires.
// localClientManager can be null if InitializeConnection returns null or depends on other lazy/async initialization steps.
var sw = Stopwatch.StartNew();
try
{
await ServerGetBasicSecureLogAsync(localClientManager, cts.Token);
}
catch(MySimpleException)
{
}
catch(OperationCancelledException)
{
}
finally
{
sw.Stop();
// could enclose cts in using statement
cts.Dispose();
}
}
// this call will never throw as long as method is catching and handling exceptions
SomeAsyncMethod().GetAwaiter().GetResult();