Die Ausnahme (n) einer Aufgabe wurden weder beim Warten auf die Aufgabe noch beim Zugriff auf ihre Ausnahmeeigenschaft beobachtet. Infolgedessen war die unbeobachtete Ausnahme

100

Was bedeutet das und wie kann es behoben werden?

Ich verwende TPL-Aufgaben.

Der ganze Fehler

Die Ausnahme (n) einer Aufgabe wurden weder beim Warten auf die Aufgabe noch beim Zugriff auf ihre Ausnahmeeigenschaft beobachtet. Infolgedessen wurde die nicht beobachtete Ausnahme vom Finalizer-Thread erneut ausgelöst.

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

mscorlib

MonsterMMORPG
quelle

Antworten:

158

Wenn Sie eine Aufgabe erstellen und niemals task.Wait()das Ergebnis von a aufrufen oder versuchen, es abzurufen Task<T>, wird die Anwendung während der Finalisierung heruntergefahren, wenn die Aufgabe vom Garbage Collector erfasst wird. Weitere Informationen finden Sie auf der MSDN-Seite zur Ausnahmebehandlung in der TPL .

Die beste Option hier ist, die Ausnahme zu "behandeln". Dies kann über eine Fortsetzung erfolgen. Sie können der Aufgabe eine Fortsetzung hinzufügen und die auftretende Ausnahme protokollieren / schlucken / usw. Dies bietet eine saubere Möglichkeit, Aufgabenausnahmen zu protokollieren, und kann als einfache Erweiterungsmethode geschrieben werden, z.

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

Mit den oben genannten Funktionen können Sie verhindern, dass eine Aufgabe die App herunterfährt und protokolliert, und zwar über:

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

Alternativ können Sie die TaskScheduler.UnobservedTaskException abonnieren und dort bearbeiten.

Reed Copsey
quelle
17
OffVerwenden Sie für zusätzliche Unterhaltung eine statische Stub-Methode in einer Klasse, die als Wort aus vier Buchstaben Ihrer Wahl bezeichnet wird, und verwenden Sie diese Methode für Ihre Sammel-Fortsetzungen. Hilft, die aufgestaute Frustration dieser besonderen Ausnahme zu bekämpfen.
Aaronaught
1
@MonsterMMORPG Ja - Sie müssen die Ausnahme grundsätzlich irgendwo abfangen oder behandeln . Solange Sie irgendwo damit umgehen, wird Ihr Kernproblem verschwinden.
Reed Copsey
1
Ist es nicht möglich, dass die Aufgabe eine Ausnahme auslöst, bevor der Aufruf von ContinueWith erfolgt?
Tim Sylvester
1
@ TimSylvester Das Framework wird es weiterhin durch die Fortsetzung abbilden, auch wenn es "bevor" die Fortsetzung angehängt wird
Reed Copsey
32
Wichtiger Hinweis: Dies ist nur erforderlich für .Net 4.0. Die Ausnahmebehandlung wurde standardmäßig geändert , .net 4.5um nicht reißen die Anwendung herunter . Weitere
Informationen finden Sie unter
43

Sicher; Dies bedeutet, dass a Taskabgeschlossen wurde, nachdem es der Speicherbereinigung überlassen wurde, aber die Aufgabe selbst fehlgeschlagen ist. Es gibt zwei Korrekturen:

  • behandeln die Aufgaben nicht direkt (Verwendung ContinueWith(...)zu unterzeichnen, und überprüfen .IsFaultedund .Exceptionauf die Taskim Parameter)
  • Behandeln Sie das TaskScheduler.UnobservedTaskExceptionEreignis und markieren Sie es als beobachtet (Aufruf e.SetObserved()nach Protokollierung des Fehlers)
Marc Gravell
quelle
4
+1 - Mit einem Zusatz - wenn Ihre Fortsetzung nichts anderes tut als das zu überprüfen IsFaulted, können Sie die OnlyOnFaultedFortsetzung Option verwenden und die manuelle Überprüfung vermeiden ...
Reed Copsey
Eigentlich geschah dies, als ich eine öffentliche statische Funktion innerhalb einer tpl-Aufgabe aufrief. Die Verwendung von try catch würde dieses Problem lösen. Muss ich wirklich eine andere Aufgabe erstellen und warten? danke
MonsterMMORPG
4
+1 für die Erwähnung, dass SetObservedon UnobservedTaskExceptionEventArgsaufgerufen werden muss.
James Webster
-17

Probier diese:

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
quelle
5
Es ist eins ??? Was meinst du? Können Sie erklären, was Ihre Antwort zu den bisherigen Antworten beiträgt?
Gert Arnold
Sie haben gerade eine neue Aufgabe erstellt, indem Sie fortfahren. Diese schlägt dann fehl und gerät in dieselbe Situation.
Robert Taylor
Diese Lösung scheint etwas kompliziert zu sein. Ich denke, Sie würden die Funktionalität unbeabsichtigt ohne Gewinn verstecken.
Velocitas