parallel library cancel c# exception task-parallel-library aggregateexception

c# - library - Aplanamiento de agregados para el procesamiento



cancel task c# (5)

Esta es una pregunta antigua, pero el problema que experimenta el OP es que await no expone la excepción AggregateException de la tarea esperada, sino la primera excepción en la excepción AggregateException. Por lo tanto, el bloque catch (AggregateException ex) se omite y la excepción se captura más arriba en la pila. Así que el código debería haber sido ''simplemente'':

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);

Alternativamente, el método de extensión WithAllExceptions de Jon Skeet le permite a uno "proteger" a AggregateException del comportamiento de await envolviendo la tarea en otra tarea para que obtenga una AggregateException que contenga una excepción AggregateException y espere "devuelve" la excepción AggregateException original / interna.

NOTA: AggregateException.Flatten realmente se "aplana" recursivamente, como se muestra en el ejemplo de la página de MSDN .

EDITAR: Se mejoró el retraso al volver a intentarlo para evitar establecer un ejemplo de async incorrecto.

Me estoy topando con algunos problemas en los que llamo flatten en una AggregateException , ¡pero dentro todavía hay OTRA AggregateException ! Esto obviamente significa que se están propagando a lo largo de la cadena y se están enrollando en otra AggregateException . ¿Hay una manera de aplanar recursivamente TODAS las excepciones internas de agregados? Por lo general, usaré el delegado de identificador para procesar estos, pero devuelve false si hay otra AggregateExceeption interna. ¿No estoy manejando esto correctamente?

EDITAR: Como ya estoy llamando a Flatten, parece que el problema es que no se detecta hasta mucho más tarde en la pila de llamadas. Aquí está el código donde llamo a Flatten (). Para usar en el seguimiento de la pila, este método se llama WriteExceptionRecord (cadena, 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);

Sin embargo, el seguimiento de la pila muestra que no se está capturando aquí. En su lugar, está siendo atrapado mucho más tarde en la pila de llamadas. A continuación se muestra la traza con cierta información de identificación eliminada por razones de seguridad:

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.<WriteExceptionRecord>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.<ExceptionRecordProcessing>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.<<ProcessBatch>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.<WriteExceptionRecord>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.<ExceptionRecordProcessing>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.<<ProcessBatch>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.<WriteExceptionRecord>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.<ExceptionRecordProcessing>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.<<ProcessBatch>b__2>d__13.MoveNext() in c:/Users/XYZ/Development/PDI/PDI/ProcessPipeline.cs:line 61<--- <--- 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.<WriteExceptionRecord>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.<ExceptionRecordProcessing>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.<<ProcessBatch>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.<WriteExceptionRecord>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.<ExceptionRecordProcessing>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.<<ProcessBatch>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.<WriteExceptionRecord>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.<ExceptionRecordProcessing>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.<<ProcessBatch>b__2>d__13.MoveNext() in c:/Users/XYZ/Development/PDI/PDI/ProcessPipeline.cs:line 61<---

Por cierto: esto es llamado por los bloques de flujo de datos TPL.


Normalmente, AggregateException se usa para consolidar múltiples fallas en un único objeto de excepción que se puede lanzar.

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


Pruebe el código de muestra a continuación, esto debería evitar await desenvuelva la excepción AggregateException y lanzar la AggregateException original en el punto donde se llama a task.result.

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


Sí, hay exactamente lo que estás pidiendo:

AggreggateException.Flatten()

pasará y comprimirá todo en una única excepción AggregateException. Así que puedes usarlo para recorrer todas las excepciones internas como esta:

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

Enlace de MSDN: http://msdn.microsoft.com/en-us/library/system.aggregateexception.flatten.aspx


Tenga en cuenta que el método ''aplanar'' le dará una lista de Excepciones, pero aún puede dejarlo con una InnerExceptions aplanada dentro de cada Excepción.

Así que encontré que esto no era realmente suficiente:

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

Debido a esta excepción:

System.Net.Http.HttpRequestException: Se produjo un error al enviar la solicitud. ---> System.Net.WebException: no se puede conectar al servidor remoto ---> System.Net.Sockets.SocketException: error de intento de conexión porque la parte conectada no respondió correctamente después de un período de tiempo o conexión establecida falló porque el host conectado no ha respondido 192.168.42.55:443 en System.Net.Sockets.Socket.EndConnect (IAsyncResult asyncResult) en System.Net.ServicePoint.ConnectSocketInternal (Boolean connectFailure, Socket s6, Socket s6, Socket & socket, IPAdaptateFailure, Socket s4, Socket s6, Socket & socket, IPAdaptateFailure, Socket s4, Socket s6, Socket & socket, , Estado ConnectSocketState, IAsyncResult asyncResult, Exception & exception) --- Fin del seguimiento interno de la pila de excepciones --- en System.Net.HttpWebRequest.EndGetRequestStream (en español). ) --- Fin del rastreo de la pila de excepción interna ---

Acabaría así:

Se produjo un error al enviar la solicitud.

La solución fue algo como esto:

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

Resultando en:

Se produjo un error al enviar la solicitud.

No se puede conectar con el servidor remoto

Falló un intento de conexión porque la parte conectada no respondió correctamente después de un período de tiempo, o falló la conexión establecida porque el host conectado no respondió 192.168.42.54:443

Espero que ayude a alguien.