2015-03-02 88 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 
    } 
}