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

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í.


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)

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

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
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.