await Task.WhenAll(tasks) 异常处理,记录来自任务的所有异常
await Task.WhenAll(tasks) Exception Handling, log all exceptions from the tasks
我想弄清楚如何报告下面代码中的任务列表抛出的所有异常。
此代码片段的基本思想是:用户向处理程序发送请求,处理程序创建消息 tasks
并将它们发送到 class,后者将它们发送到外部系统.我包括了下面涉及的方法。
我一定有什么不对,因为我正在调试异常处理程序,任务异常总是空的,因为它们的状态似乎是 Waiting for Activiation
,除非我在断点停留足够长的时间。
// Handle the user request
public async void Handle(WriteScanToSys settings)
{
_successfulScanIds = new List<int>();
// create the messages as tasks
var tasks = _factory.CreateMessage(settings).Select(msg => SendScans(msg));
try
{
// wait for all of them to complete
await Task.WhenAll(tasks); // I had ConfigureAwait(false) here, but took it off
}
catch (Exception)
{
foreach (var task in tasks.Where(t => t.Exception != null))
{
// ELMAH
var errorLog = ErrorLog.GetDefault(null);
errorLog.Log(new Error(task.Exception));
}
}
// save to repository
}
// the task to perform
private async Task<IDictionary<string, object>> SendScans(IDictionary<string, object> data)
{
object sysMsg = null;
var response = await _msgCenter.SendMessage(data);
response.TryGetValue("SystemMessage", out sysMsg);
_successfulScanIds.Add(Convert.ToInt32(data["Id"]));
return response;
}
// the communication with the external system (The message center class)
private async Task<IDictionary<string, object>> SendMessage(IDictionary<string, object> msg)
{
var response = new Dictionary<string, object>();
var response = await _client.sendAsync(
new BodyOfRequest(
// Compose Object
));
if (response.ScreenMessage != "SUCCESSFUL")
throw new CustomException("The transaction for job " + job + " failed with msg: " + body.ScreenMessage);
response.Add("SystemMessage", body.ScreenMessage);
return response;
}
您犯了懒惰求值的错误 - Select
的结果将在您每次迭代它时创建一组新任务。您可以通过调用 ToList()
:
来解决这个问题
var tasks = _factory.CreateMessage(settings)
.Select(msg => SendScans(msg))
.ToList();
这样,您正在等待的任务集将与您的 foreach
循环检查的任务集相同。
您可以从 Task.WhenAll
-Task:
中获取异常(如果有),而不是遍历所有任务
var taskResult = Task.WhenAll(tasks);
try
{
await taskResult;
}
catch (Exception e)
{
if (taskResult.IsCanceled)
{
// Cancellation is most likely due to a shared cancellation token. Handle as needed, possibly check if ((TaskCanceledException)e).CancellationToken == token etc.
}
else if (taskResult.IsFaulted)
{
// use taskResult.Exception which is an AggregateException - which you can iterate over (it's a tree! .Flatten() might help)
// caught exception is only the first observed exception
}
else
{
// Well, this should not really happen because it would mean: Exception thrown, not faulted nor cancelled but completed
}
}
我想弄清楚如何报告下面代码中的任务列表抛出的所有异常。
此代码片段的基本思想是:用户向处理程序发送请求,处理程序创建消息 tasks
并将它们发送到 class,后者将它们发送到外部系统.我包括了下面涉及的方法。
我一定有什么不对,因为我正在调试异常处理程序,任务异常总是空的,因为它们的状态似乎是 Waiting for Activiation
,除非我在断点停留足够长的时间。
// Handle the user request
public async void Handle(WriteScanToSys settings)
{
_successfulScanIds = new List<int>();
// create the messages as tasks
var tasks = _factory.CreateMessage(settings).Select(msg => SendScans(msg));
try
{
// wait for all of them to complete
await Task.WhenAll(tasks); // I had ConfigureAwait(false) here, but took it off
}
catch (Exception)
{
foreach (var task in tasks.Where(t => t.Exception != null))
{
// ELMAH
var errorLog = ErrorLog.GetDefault(null);
errorLog.Log(new Error(task.Exception));
}
}
// save to repository
}
// the task to perform
private async Task<IDictionary<string, object>> SendScans(IDictionary<string, object> data)
{
object sysMsg = null;
var response = await _msgCenter.SendMessage(data);
response.TryGetValue("SystemMessage", out sysMsg);
_successfulScanIds.Add(Convert.ToInt32(data["Id"]));
return response;
}
// the communication with the external system (The message center class)
private async Task<IDictionary<string, object>> SendMessage(IDictionary<string, object> msg)
{
var response = new Dictionary<string, object>();
var response = await _client.sendAsync(
new BodyOfRequest(
// Compose Object
));
if (response.ScreenMessage != "SUCCESSFUL")
throw new CustomException("The transaction for job " + job + " failed with msg: " + body.ScreenMessage);
response.Add("SystemMessage", body.ScreenMessage);
return response;
}
您犯了懒惰求值的错误 - Select
的结果将在您每次迭代它时创建一组新任务。您可以通过调用 ToList()
:
var tasks = _factory.CreateMessage(settings)
.Select(msg => SendScans(msg))
.ToList();
这样,您正在等待的任务集将与您的 foreach
循环检查的任务集相同。
您可以从 Task.WhenAll
-Task:
var taskResult = Task.WhenAll(tasks);
try
{
await taskResult;
}
catch (Exception e)
{
if (taskResult.IsCanceled)
{
// Cancellation is most likely due to a shared cancellation token. Handle as needed, possibly check if ((TaskCanceledException)e).CancellationToken == token etc.
}
else if (taskResult.IsFaulted)
{
// use taskResult.Exception which is an AggregateException - which you can iterate over (it's a tree! .Flatten() might help)
// caught exception is only the first observed exception
}
else
{
// Well, this should not really happen because it would mean: Exception thrown, not faulted nor cancelled but completed
}
}