Сглаживание совокупных исключений для обработки

Я сталкиваюсь с несколькими проблемами, когда я вызываю flatten в AggregateException , но внутри есть еще ДРУГОЕ AggregateException Исключение! Это, очевидно, означает, что они распространяются по цепочке и превращаются в другое AggregateException . Есть ли способ рекурсивно сгладить ВСЕ внутренние Агрегатные Исключения? Обычно я использую делегат дескриптора для их обработки, но он возвращает false, если есть другое внутреннее агрегированное выражение. Разве я не правильно их обрабатываю?

EDIT: Поскольку я уже звоню в Flatten, кажется, что проблема заключается в том, что он не поймается до конца в стоп-кадре. Вот код, который я называю Flatten (). Для использования в трассировке стека этот метод называется WriteExceptionRecord (string, FileInfo):

 do { try { using (var stream = file.Open(FileMode.Append, FileAccess.Write, FileShare.None)) { using (StreamWriter writer = new StreamWriter(stream)) { await writer.WriteLineAsync(data); } } } catch (AggregateException ex) { ex.Flatten().Handle((x) => { if (x is IOException) { retryNeeded = true; retryLeft--; Thread.Sleep(500); return true; } logger.ErrorException("Could not write to exception file: " + data, ex); return false; }); } } while (retryNeeded && retryLeft > 0); 

Тем не менее, трассировка стека показывает, что она не попадает сюда. Вместо этого он пойман позже в стек вызовов. Ниже приведена трассировка с некоторой идентифицирующей информацией, удаленной по соображениям безопасности:

 System.AggregateException: One or more errors occurred. ---> System.AggregateException: One or more errors occurred. ---> System.IO.IOException: The process cannot access the file 'X:\Production\ProductionBatches\DataEntry\J\PD\Exception.csv' because it is being used by another process. at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath) at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost) at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share) at System.IO.FileInfo.Open(FileMode mode, FileAccess access, FileShare share) at PDI.LoadFileProcessing.d__21.MoveNext() in c:\Users\XYZ\Development\PDI\PDI\LoadFileProcessing.cs:line 328 --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter.GetResult() at PDI.LoadFileProcessing.d__17.MoveNext() in c:\Users\XYZ\Development\PDI\PDI\LoadFileProcessing.cs:line 316 --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter.GetResult() at PDI.ProcessPipeline.c__DisplayClass9.<b__2>d__13.MoveNext() in c:\Users\XYZ\Development\PDI\PDI\ProcessPipeline.cs:line 61 --- End of inner exception stack trace --- --- End of inner exception stack trace --- ---> (Inner Exception #0) System.AggregateException: One or more errors occurred. ---> System.IO.IOException: The process cannot access the file 'X:\Production\ProductionBatches\DataEntry\J\PD\Exception.csv' because it is being used by another process. at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath) at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost) at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share) at System.IO.FileInfo.Open(FileMode mode, FileAccess access, FileShare share) at PeopleDocImporter.LoadFileProcessing.d__21.MoveNext() in c:\Users\XYZ\Development\PDI\PDI\LoadFileProcessing.cs:line 328 --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter.GetResult() at PDI.LoadFileProcessing.d__17.MoveNext() in c:\Users\XYZ\Development\PDI\PDI\LoadFileProcessing.cs:line 316 --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter.GetResult() at PDI.ProcessPipeline.c__DisplayClass9.<b__2>d__13.MoveNext() in c:\Users\XYZ\Development\PDI\PDI\ProcessPipeline.cs:line 61 --- End of inner exception stack trace --- ---> (Inner Exception #0) System.IO.IOException: The process cannot access the file 'X:\Production\ProductionBatches\DataEntry\J\PD\Exception.csv' because it is being used by another process. at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath) at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost) at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share) at System.IO.FileInfo.Open(FileMode mode, FileAccess access, FileShare share) at PDI.LoadFileProcessing.d__21.MoveNext() in c:\Users\XYZ\Development\PDI\PDI\LoadFileProcessing.cs:line 328 --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter.GetResult() at PDI.LoadFileProcessing.d__17.MoveNext() in c:\Users\XYZ\Development\PDI\PDI\LoadFileProcessing.cs:line 316 --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter.GetResult() at PDI.ProcessPipeline.c__DisplayClass9.<b__2>d__13.MoveNext() in c:\Users\XYZ\Development\PDI\PDI\ProcessPipeline.cs:line 61<---  System.AggregateException: One or more errors occurred. ---> System.IO.IOException: The process cannot access the file 'X:\Production\ProductionBatches\DataEntry\J\PD\Exception.csv' because it is being used by another process. at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath) at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost) at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share) at System.IO.FileInfo.Open(FileMode mode, FileAccess access, FileShare share) at PDI.LoadFileProcessing.d__21.MoveNext() in c:\Users\XYZ\Development\PDI\PDI\LoadFileProcessing.cs:line 328 --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter.GetResult() at PDI.LoadFileProcessing.d__17.MoveNext() in c:\Users\XYZ\Development\PDI\PDI\LoadFileProcessing.cs:line 316 --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter.GetResult() at PDI.ProcessPipeline.c__DisplayClass9.<b__2>d__13.MoveNext() in c:\Users\XYZ\Development\PDI\PDI\ProcessPipeline.cs:line 61 --- End of inner exception stack trace --- ---> (Inner Exception #0) System.AggregateException: One or more errors occurred. ---> System.IO.IOException: The process cannot access the file 'X:\J\PD\Exception.csv' because it is being used by another process. at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath) at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost) at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share) at System.IO.FileInfo.Open(FileMode mode, FileAccess access, FileShare share) at PDI.LoadFileProcessing.d__21.MoveNext() in c:\Users\XYZ\Development\PDI\PDI\LoadFileProcessing.cs:line 328 --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter.GetResult() at PDI.LoadFileProcessing.d__17.MoveNext() in c:\Users\XYZ\Development\PDI\PDI\LoadFileProcessing.cs:line 316 --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter.GetResult() at PDI.ProcessPipeline.c__DisplayClass9.<b__2>d__13.MoveNext() in c:\Users\XYZ\Development\PDI\PDI\ProcessPipeline.cs:line 61 --- End of inner exception stack trace --- ---> (Inner Exception #0) System.IO.IOException: The process cannot access the file 'X:\Production\ProductionBatches\DataEntry\J\PD\Exception.csv' because it is being used by another process. at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath) at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost) at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share) at System.IO.FileInfo.Open(FileMode mode, FileAccess access, FileShare share) at PDI.LoadFileProcessing.d__21.MoveNext() in c:\Users\XYZ\Development\PDI\PDI\LoadFileProcessing.cs:line 328 --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter.GetResult() at PDI.LoadFileProcessing.d__17.MoveNext() in c:\Users\XYZ\Development\PDI\PDI\LoadFileProcessing.cs:line 316 --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter.GetResult() at PDI.ProcessPipeline.c__DisplayClass9.<b__2>d__13.MoveNext() in c:\Users\XYZ\Development\PDI\PDI\ProcessPipeline.cs:line 61<--- 

Кстати: это вызывается блоками TPL-Dataflow.

Да, именно о чем вы просите:

 AggreggateException.Flatten() 

будет проходить и сжимать все до одного исключения AggregateException. Таким образом, вы можете использовать его для прокрутки всех внутренних исключений, таких как:

 try { // something dangerous } catch (AggregateException ae) { foreach(var innerException in ae.Flatten().InnerExceptions) { // handle error } } 

Ссылка MSDN: http://msdn.microsoft.com/en-us/library/system.aggregateexception.flatten.aspx

Имейте в виду, что метод «flatten» предоставит вам список Исключений, но все равно может оставить вас с плоскими внутренними исключениями внутри каждого Исключения.

Поэтому я обнаружил, что этого было недостаточно:

 try { // something dangerous } catch (AggregateException ae) { foreach(Exception innerException in ae.Flatten().InnerExceptions) { Console.WriteLine(innerException.Message()); } } 

Потому что это исключение:

System.Net.Http.HttpRequestException: при отправке запроса произошла ошибка. —> System.Net.WebException: невозможно подключиться к удаленному серверу —> System.Net.Sockets.SocketException: попытка подключения завершилась неудачно, потому что связанная сторона не ответила должным образом через какое-то время или установив соединение не удалось, потому что подключенный хост не смог ответить 192.168.42.55:443 в System.Net.Sockets.Socket.EndConnect (IAsyncResult asyncResult) в System.Net.ServicePoint.ConnectSocketInternal (Boolean connectFailure, Socket s4, Socket s6, Socket & socket, IPAddress & address , Состояние ConnectSocketState, IAsyncResult asyncResult, исключение и исключение) — Конец внутренней трассировки стека — в System.Net.HttpWebRequest.EndGetRequestStream (IAsyncResult asyncResult, TransportContext & context) в System.Net.Http.HttpClientHandler.GetRequestStreamCallback (IAsyncResult ar ) — Конец внутренней проверки стека исключений —

Это закончится следующим образом:

При отправке запроса произошла ошибка.

Исправление было примерно таким:

 foreach(Exception exInnerException in aggEx.Flatten().InnerExceptions) { Exception exNestedInnerException = exInnerException; do { if (!string.IsNullOrEmpty(exNestedInnerException.Message)) { Console.WriteLine(exNestedInnerException.Message); } exNestedInnerException = exNestedInnerException.InnerException; } while (exNestedInnerException != null); } 

В результате чего:

При отправке запроса произошла ошибка.

невозможно подключиться к удаленному серверу

Не удалось выполнить попытку подключения, потому что связанная сторона не ответила должным образом через некоторое время или установив соединение не удалось, поскольку подключенный хост не смог ответить 192.168.42.54:443

Надежда помогает кому-то.

Это старый вопрос, но проблема, с которой сталкивается OP, заключается в том, что ожидание не выдает AggregateException из ожидаемой задачи, а вместо этого просто первое исключение в исключении AggregateException. Таким образом, блок catch (AggregateException ex) исключается, и исключение попадает в стек вверх. Таким образом, код должен быть «просто»:

 retryNeeded = false; do { try { if (retryNeeded) await Task.Delay(500); // substituted for Thread.Sleep using (var stream = file.Open(FileMode.Append, FileAccess.Write, FileShare.None)) { using (StreamWriter writer = new StreamWriter(stream)) { await writer.WriteLineAsync(data); retryNeeded = false; } } } catch (IOException) { retryNeeded = true; retryLeft--; } catch (Exception ex) { logger.ErrorException("Could not write to exception file: " + data, ex); throw; } } while (retryNeeded && retryLeft > 0); return (retryLeft > 0); 

В качестве альтернативы, метод расширения метода WithAllExceptions от Jon Skeet позволяет «защищать» поведение AggregateException от ожидания, завершая задачу в другой задаче, поэтому вы получаете исключение AggregateException, содержащее исключение AggregateException и ожидающее «возвращает» исходное / внутреннее исключение AggregateException.

ПРИМЕЧАНИЕ. AggregateException.Flatten действительно «сглаживает» рекурсивно, как показано в примере на странице MSDN .

EDIT: улучшена задержка при повторном вызове, чтобы избежать установки плохого асинхронного примера.

Обычно AggregateException используется для объединения нескольких сбоев в один, бросающийся объект исключений.

 try { Task.WaitAll(tasks) } catch (AggregateException ae) { ae.Handle((x) => { if (x is UnauthorizedAccessException) // This we know how to handle. { //do your code here } return true; //if you do something like this all exceptions are marked as handled }); } 

Попробуйте пример кода ниже, это должно избегать разворачивания исключения AggregateException и выбросить исходное значение AggregateException в точке, где вызывается task.result.

 var task = writer.WriteLineAsync(data); await task.ContinueWith(t => { }, TaskContinuationOptions.ExecuteSynchronously)); return task.Result;