No se observaron las excepciones de una tarea ni al esperar en la tarea ni al acceder a su propiedad de excepción. Como resultado, la excepción no observada fue

100

¿Qué significa esto y cómo solucionarlo?

Estoy usando tareas de TPL.

Todo el error

No se observaron las excepciones de una tarea ni al esperar en la tarea ni al acceder a su propiedad de excepción. Como resultado, el subproceso del finalizador volvió a generar la excepción no observada.

en System.Threading.Tasks.TaskExceptionHolder.Finalize ()

mscorlib

MonstruoMMORPG
fuente

Respuestas:

158

Si crea una tarea y nunca llama task.Wait()ni intenta recuperar el resultado de una Task<T>, cuando la tarea es recopilada por el recolector de basura, derribará su aplicación durante la finalización. Para obtener más información, consulte la página de MSDN sobre Manejo de excepciones en el TPL .

La mejor opción aquí es "manejar" la excepción. Esto se puede hacer a través de una continuación: puede adjuntar una continuación a la tarea y registrar / tragar / etc. la excepción que ocurre. Esto proporciona una forma limpia de registrar las excepciones de tareas y se puede escribir como un método de extensión simple, es decir:

public static void LogExceptions(this Task task)
{
    task.ContinueWith( t =>
    {
         var aggException = t.Exception.Flatten();
         foreach(var exception in aggException.InnerExceptions)
             LogException(exception);
    }, 
    TaskContinuationOptions.OnlyOnFaulted);
}

Con lo anterior, puede evitar que cualquier tarea elimine la aplicación y la registre a través de:

Task.Factory.StartNew( () => 
   { 
       // Do your work...
   }).LogExceptions();

Alternativamente, puede suscribirse a TaskScheduler.UnobservedTaskException y manejarlo allí.

Reed Copsey
fuente
17
Para mayor entretenimiento, tenga un método de código auxiliar estático Offen una clase nombrada como la palabra de cuatro letras de su elección, y úselo para sus continuaciones generales. Ayuda a combatir parte de la frustración acumulada por esta excepción en particular.
Aaronaught
1
@MonsterMMORPG Sí, básicamente tienes que detectar o manejar la excepción en alguna parte . Mientras lo maneje en alguna parte, su problema central desaparecerá.
Reed Copsey
1
¿No es posible que la tarea arroje una excepción antes de que se realice la llamada a ContinueWith?
Tim Sylvester
1
@TimSylvester El marco aún lo mapeará a través de la continuación, incluso si sucede "antes" de que se adjunte la continuación
Reed Copsey
32
Nota importante: esto solo es necesario para .Net 4.0. El manejo de excepciones se cambió de forma predeterminada .net 4.5para no derribar la aplicación . Vea más en Manejo de excepciones de tareas en .NET 4.5
i3arnon
43

Por supuesto; significa que Taskse finalizó después de dejarlo en la recolección de basura, pero la tarea en sí falló. Hay dos correcciones:

  • manejar las tareas fallan directa (utilización ContinueWith(...)de suscripción, y comprobar .IsFaultedy .Exceptionen el Tasken el parámetro)
  • manejar el TaskScheduler.UnobservedTaskExceptionevento y marcarlo como observado (llamar e.SetObserved()después de registrar el error)
Marc Gravell
fuente
4
+1 - Con una adición: si su continuación no hace nada más que verificar IsFaulted, puede usar la OnlyOnFaultedopción de continuación y evitar la verificación manual ...
Reed Copsey
en realidad, esto sucedió cuando llamé a una función estática pública dentro de una tarea tpl. usar try catch resolvería este problema? ¿Realmente necesito crear otra tarea y esperar? gracias
MonsterMMORPG
4
1 de mencionar que SetObservedel UnobservedTaskExceptionEventArgstiene que ser llamado.
James Webster
-17

Prueba este:

public static void ThrowFirstExceptionIfHappens(this Task task)
{
    task.ContinueWith(t =>
    {
        var aggException = t.Exception.Flatten();
        foreach (var exception in aggException.InnerExceptions)
        {
            throw exception; // throw only first, search for solution
        }
    },
    TaskContinuationOptions.OnlyOnFaulted); // not valid for multi task continuations
}

public static Task CreateHandledTask(Action action) 
{
    Task tsk = Task.Factory.StartNew(action);
    tsk.ThrowFirstExceptionIfHappens();
    return tsk;
}
h4165f8ghd4f854d6f8h
fuente
5
¿Es uno ??? ¿Qué quieres decir? ¿Podría explicar en qué contribuye su respuesta a las respuestas hasta ahora?
Gert Arnold
acaba de crear una nueva tarea al continuar, que luego fallará y se encontrará en la misma situación.
Robert Taylor
Esta solución parece un poco complicada. Creo que estarías ocultando la funcionalidad de forma involuntaria sin ningún beneficio.
Velocitas