2015-03-02 111 views
5

我试图找出如何报告从下面的代码任务的列表抛出的所有异常记录所有的异常。等待Task.WhenAll(任务)异常处理,从任务

该代码片段的基本思想是:用户向处理程序发送请求,处理程序创建消息tasks并将它们发送给将它们发送到外部系统的类。我包括下面介绍的方法。

我必须要关闭一些东西,因为我在调试异常处理程序,并且任务Exception总是为空,因为它的状态似乎是Waiting for Activiation,除非我保持足够长的断点。

我使用这个链接Task Continuations will not Handle your Exceptions作为参考上手。懒惰的评价

// 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; 
} 

回答

7

你已经爱上犯规 - 的Select结果将创建一组新的任务在每次迭代它的时间。您只需通过调用ToList()解决这个问题:

var tasks = _factory.CreateMessage(settings) 
        .Select(msg => SendScans(msg)) 
        .ToList(); 

这样设定的,你等待将是相同的一组任务,您foreach循环检查的任务。

+0

你知道,我想过,但糟了当时的一个原因我现在无法真正想到。我应该知道这一点,尤其是当调试器在尝试钻入任务时无法评估任务时。有时候我想这需要别人的眼睛。谢谢@JonSkeet – 2015-03-02 16:50:48

1

相反遍历所有的任务,你可以从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 
    } 
}