2017-02-28 1 views
1

Wenn ich eine Reihe von Methoden zum Aufruf haben, und dies asynchron tun möchten. Ich kann dies tun:Wie setze ich eine Reihe von asynchronen Aufgaben in C# und Handle Fehler mit der Quelle

var status = new DiagnosticsResult(); 

try 
{ 
    var taskList = new List<Task> 
    { 
     _someService.Method1(), 
     _someService.Method2(), 
     _someService.Method3(), 
     _someService.Method4(), 
     _someService.Method5(), 
     _someService.Method6(), 
     _someService.Method7(), 
     _someService.Method8() 
    }; 

    Task.WaitAll(taskList.ToArray()); 
} 
catch (AggregateException ex) 
{ 
    foreach (var innerException in ex.InnerExceptions) 
    { 
     // Do Something 
    } 
} 

Und das ist in Ordnung, wenn ich will nur wissen, dass ein Fehler hat aufgetreten ist, aber was ist, wenn ich muss wissen, welche Methoden werfen eine Ausnahme und welche gelungen?

+0

Können Sie den Stack-Trace für jede Ausnahme verwenden? Das sollte Ihnen für jeden Fehler zeigen, welche Methode die Ausnahme verursacht hat. – GSkidmore

+0

Wenn ich Ihren Code verwende, kann ich 'innerException.TargetSite.Name' und einige Zeichenfolgenmanipulation verwenden, um den Methodennamen zu erhalten, wenn Sie das suchen. Für mich hat ein Methodenname Method1 eine TargetSite.Name von ' b__2_0' –

Antwort

1

Wenn Sie Ihre Liste der Aufgaben im Rahmen halten können Sie über sie iterieren in Ihrem catch oder einfach nach dem Wait auf Task.Exception für Ausnahmen zu suchen.

Sie können AggregateException.Handle mit einem Func<Exception, bool> verwenden, die Sie auf die Nachricht filtern lassen, der Art usw. Zusätzlich, wenn Sie die Aggregate iterieren Sie Flatten aufreihen alle Ausnahmen nennen sollte.

Exception handling MSDN

bearbeiten

Das Problem, das ich bin vor, dass sobald man den Rest Schalte auf Abgebrochen Zustand führt. Ich brauche sie alle, um zu laufen und zu bestehen oder zu versagen, dann muss ich das Ergebnis bestimmen. Ich zog die Aufgabenliste außerhalb des try und ja, es wird aktualisiert, aber ich habe 3 „RanToCompletion“, 1 „Fehlerhaft“ und der Rest „Abgebrochen“, wenn # 4 nicht

Es scheint, als ob der Ansatz wäre, auf jeden warten und ihre Ausnahmen einzeln behandeln anstatt als Gruppe. Zwei Ansätze unten gezeigt:

public async Task Test1() { 
    var taskList = new List<Task>() { 
     _someService.Method1.ContinueWith(tsk => { 
      //handle ex 
     }).Unwrap() 
    } 
    /* 
    * or.. 
    * */ 
    try { 
     await _someService.Method1 
    }catch (AggregateException ex) { 
     /*** 
     * Handle ex 
     * *// 
    }    
} 
+0

Das Problem, das ich gegenüberstelle, ist, dass, sobald man den Rest in den Status Canceled versetzt. Ich brauche sie alle, um zu laufen und zu bestehen oder zu versagen, dann muss ich das Ergebnis bestimmen. Ich habe die Aufgabenliste außerhalb des Versuchs verschoben und ja es wird aktualisiert, aber ich bekomme 3 "RanToCompletion", 1 "Faulted" und den Rest "Cancelled", wenn # 4 fehlschlägt. –

+0

Nur ein Gedanke haben Sie überprüft das Verhalten von 'WhenAll 'wahrscheinlich das gleiche, aber es lohnt sich zu überprüfen. Sonst gibt 'erwarten' jeweils dasselbe, was nur die Ausnahme in 'ContinueWith' und' harring' von 'Unwrap' einfängt ... nicht elegant, aber funktionstüchtig. – JSteward

+0

Ich war immer auf dem Laufenden, was ich hatte - und arbeitete.- Ich suchte nach etwas eleganterem, aber ich fange an zu denken, dass ich an erster Stelle richtig gewesen wäre:/ –

0

Ein möglicher Ansatz wird mit jeder Aufgabe in einem Token-Passing und Korrelation ermöglichen bei der Bewertung des Ergebnisses:

public static Task<WhenAllWithTokenResult<TToken>> WhenAllWithToken<TToken>(Tuple<Task, TToken>[] tasks) 
{ 
    var successfulTasks = new List<Tuple<Task, TToken>>(); 
    var failedTasks = new List<Tuple<Task, TToken>>(); 
    var cancelledTasks = new List<Tuple<Task, TToken>>(); 
    int amountCompleted = 0; 
    var taskCompletionSource = new TaskCompletionSource<WhenAllWithTokenResult<TToken>>(); 
    // Register ContinueWith callback for each task and add it to the according result list when completed 
    foreach (var tuple in tasks) 
    { 
     var copyOfTuple = tuple; 
     tuple.Item1.ContinueWith(_ => 
     {    
      if (_.IsFaulted) 
      { 
       failedTasks.Add(copyOfTuple); 
      } 
      else if (_.IsCanceled) 
      { 
       cancelledTasks.Add(copyOfTuple); 
      } 
      else if (_.IsCompleted) 
      { 
       successfulTasks.Add(copyOfTuple); 
      } 
      if (Interlocked.Increment(ref amountCompleted) == tasks.Length) 
      { 
       // All tasks finished so let's set the result of this method 
       taskCompletionSource.SetResult(new WhenAllWithTokenResult<TToken>(successfulTasks, failedTasks, cancelledTasks)); 
      } 
     }); 
    } 
    return taskCompletionSource.Task; 
} 

public class WhenAllWithTokenResult<TToken> 
{ 
    public IList<Tuple<Task, TToken>> SuccessfulTasks { get; private set; } 
    public IList<Tuple<Task, TToken>> FailedTasks { get; private set; } 
    public IList<Tuple<Task, TToken>> CancelledTasks { get; private set; } 

    public WhenAllWithTokenResult(IList<Tuple<Task, TToken>> successfulTasks, IList<Tuple<Task, TToken>> failedTasks, IList<Tuple<Task, TToken>> cancelledTasks) 
    { 
     CancelledTasks = cancelledTasks; 
     SuccessfulTasks = successfulTasks; 
     FailedTasks = failedTasks; 
    } 
} 

und dessen Verwendung mag:

WhenAllWithTokenResult<string> result = 
    await WhenAllWithToken(
        new[] 
        { 
         Tuple.Create(_someService.Method1(), "Method1"), 
         Tuple.Create(_someService.Method2(), "Method2"), 
         Tuple.Create(_someService.Method3(), "Method3"), 
         Tuple.Create(_someService.Method4(), "Method4") 
        }); 

foreach (var item in result.SuccessfulTasks) 
{ 
    Console.WriteLine("Successful: {0}", item.Item2); 
} 
foreach (var item in result.FailedTasks) 
{ 
    Console.WriteLine("Failed: {0}", item.Item2); 
} 
foreach (var item in result.CancelledTasks) 
{ 
    Console.WriteLine("Cancelled: {0}", item.Item2); 
} 

Bitte beachten Sie, 1) Das Token ist ein generisches und nur weitergegeben, um die Korrelation zu ermöglichen. Also, es kann alles sein, was du willst. 2) WhenAllWithToken hat eine andere Semantik als WhenAll: Es gibt eine Aufgabe zurück, die abgeschlossen ist, wenn alle Eingabeaufgaben entweder erfolgreich waren, fehlgeschlagen oder abgebrochen wurden, aber vorher nicht.

Verwandte Themen