2017-03-01 1 views
0

Die Run() Methode (erster Codeblock) ruft GetImpairedNodesFromCASpectrumAsync() auf, die wiederum einen Anruf an GetRoutersOn3GBackupNodeStatusesAsync() macht.C# TPL Task propagate Ausnahmen - Mehrstufige Aufgabe

Derzeit, wenn eine der Aufgaben in GetRoutersOn3GBackupNodeStatusesAsync() (aufgrund einer Ausnahme) fehlschlagen, bekomme ich eine sehr generische Ausnahme in der Run() Methode, die besagt, dass die Aufgabe abgebrochen wurde.

Wie kann ich sicherstellen, dass alle Tasks in meinem Aufrufstack die ursprüngliche Exception zurück an die run-Methode senden, damit ich sie dort behandeln kann?

public override void Run(ref DevOpsScheduleEntryEventCollection events) 
{ 
    // I want to be able to catch any exceptions thrown from tasks in GetRoutersOn3GBackupNodeStatusesAsync() 

    Task<NetworkDeviceNodeStatus[]> CasImapairedNodesTask = 
       CasOperations.GetImpairedNodesFromCASpectrumAsync(); 
    Task.WaitAll(CasImapairedNodesTask); 
    NetworkDeviceNodeStatus[] CasImpairedNodes = CasImapairedNodesTask.Result.ToArray(); 
} 

internal virtual async Task<NetworkDeviceNodeStatus[]> GetImpairedNodesFromCASpectrumAsync() 
{ 
#if DEBUG 
    Debug.WriteLine("Entering GetNodesInCriticalCondition()"); 
    Stopwatch sw = new Stopwatch(); 
    sw.Start(); 
#endif 

    // Execute both tasks. Throw an Exception if any errors. 
    try { 
     var nodesWithCircuitsDown = new List<NetworkDeviceNodeStatus>(); 

     Task<NetworkDeviceNodeStatus[]> getAlarmingRoutersStatusesTask = null; 
     Task<NetworkDeviceNodeStatus[]> getActive3GRoutersStatusesTask = null; 

     getAlarmingRoutersStatusesTask = GetAlarmingRouterNodeStatusesAsync(); 
     getActive3GRoutersStatusesTask = GetRoutersOn3GBackupNodeStatusesAsync(); 

     await getAlarmingRoutersStatusesTask; 
     await getActive3GRoutersStatusesTask; 

     var threeGNodeStatuses = new List<NetworkDeviceNodeStatus>(); 
     var offlineNodeStatuses = new List<NetworkDeviceNodeStatus>(); 


     // Check if any nodes were hard down, but quickly came up on 3G 
     foreach (var status in getAlarmingRoutersStatusesTask.Result) { 
      var threeGStatus = getActive3GRoutersStatusesTask.Result. 
       FirstOrDefault(x => x.DeviceRetrievalId == status.DeviceRetrievalId); 

      if (threeGStatus == null) { 
       offlineNodeStatuses.Add(status); 
      } 
     } 

     foreach (var status in getActive3GRoutersStatusesTask.Result) { 
      threeGNodeStatuses.Add(status); 
     } 

     nodesWithCircuitsDown.AddRange(threeGNodeStatuses); 
     nodesWithCircuitsDown.AddRange(offlineNodeStatuses); 

     Trace.TraceInformation("{0} nodes with main data circuit down.", nodesWithCircuitsDown.Count); 
#if DEBUG 
     sw.Stop(); 
     Debug.WriteLine("Leaving GetNodesInCriticalCondition(). [" + sw.Elapsed.TotalSeconds + "]"); 
#endif 
     return nodesWithCircuitsDown.ToArray(); 
    } catch (AggregateException ae) { 
     StringBuilder sb = new StringBuilder(); 
     foreach (var e in ae.Flatten().InnerExceptions) { 
      sb.Append(e.Message + "\n"); 
     } 
     throw new Exception("One of more errors occured while retrieving impaired nodes.\n" + sb.ToString()); 
    } 
} 

virtual internal async Task<NetworkDeviceNodeStatus[]> GetRoutersOn3GBackupNodeStatusesAsync() 
{ 
    List<Branch3GInfo> branchActive3GInfos = new List<Branch3GInfo>(); 

    var nodeStatuses = new List<NetworkDeviceNodeStatus>(); 
    Task<Branch3GInfo[]> getActive3GRoutersTask = GetNodesOn3GBackupAsyncInternal(); 
    NetworkDeviceNodeStatus[] deviceStatuses = new NetworkDeviceNodeStatus[0]; 

    Task getBasicInfoTasks = await getActive3GRoutersTask.ContinueWith(async x => 
    { 
     branchActive3GInfos = x.Result.Where(y => y.Status == Branch3GInfo.Branch3GStatus.Active).ToList(); 
     Trace.TraceInformation("Found " + x.Result.Count() + " CAS Nodes on 3G backup."); 

     foreach (var branchActive3GInfo in branchActive3GInfos) { 
      await branchActive3GInfo.RouterInfo.GetBasicInfoAsync(); 
      Trace.TraceInformation("Retrieved ModelBasicInfo for " 
       + branchActive3GInfo.RouterInfo.GetBasicInfo()); 
     } 

    }, TaskContinuationOptions.OnlyOnRanToCompletion); 

    await getBasicInfoTasks.ContinueWith(x => 
    { 
     deviceStatuses = GetNetworkDeviceNodeStatuses(branchActive3GInfos.ToArray()); 
     return deviceStatuses; 
    }, TaskContinuationOptions.OnlyOnRanToCompletion); 

    return deviceStatuses; 
} 
+0

Warum sind Sie Task.WaitAll (CasImapairedNodesTask) zu verwenden, wenn CasImapairedNodesTask nur eine einzige Aufgabe ist? –

+0

[Async-Ausnahmebehandlung] (https://msdn.microsoft.com/en-us/library/dd997415 (v = vs.110) .aspx), Sind Sie sicher, dass Sie keine 'AggregateException' sehen? – JSteward

+0

@BrandonKramer Alter Code, früher waren es mehrere Aufgaben. – blgrnboy

Antwort

2

Ihr Problem ist aufgrund ContinueWith, die ihre Fortsetzung stornieren, wenn die Bedingungen nicht erfüllt sind (das heißt, TaskContinuationOptions.OnlyOnRanToCompletion).

Als allgemeine Regel gilt, verwenden await statt ContinueWith:

virtual internal async Task<NetworkDeviceNodeStatus[]> GetRoutersOn3GBackupNodeStatusesAsync() 
{ 
    List<Branch3GInfo> branchActive3GInfos = new List<Branch3GInfo>(); 

    var nodeStatuses = new List<NetworkDeviceNodeStatus>(); 
    NetworkDeviceNodeStatus[] deviceStatuses = new NetworkDeviceNodeStatus[0]; 
    var result = GetNodesAsync(); 
    deviceStatuses = GetNetworkDeviceNodeStatuses(branchActive3GInfos.ToArray()); 
    return deviceStatuses; 
} 

private async Task<Branch3GInfo[]> GetNodesAsync() 
{ 
    var result = await GetNodesOn3GBackupAsyncInternal(); 
    branchActive3GInfos = result.Where(y => y.Status == Branch3GInfo.Branch3GStatus.Active).ToList(); 
    Trace.TraceInformation("Found " + x.Result.Count() + " CAS Nodes on 3G backup."); 

    foreach (var branchActive3GInfo in branchActive3GInfos) { 
    await branchActive3GInfo.RouterInfo.GetBasicInfoAsync(); 
    Trace.TraceInformation("Retrieved ModelBasicInfo for " 
      + branchActive3GInfo.RouterInfo.GetBasicInfo()); 
    } 
    return result; 
} 
Verwandte Themen