D'après mes recherches, je l'ai appris ce qui suit:TaskScheduler.UnobservedTaskException ne sera jamais appelé
TaskScheduler.UnobservedTaskException
doit attendre que la tâche à déchets collectés avant de cette exception inobservée tâche se propagera jusqu'au casUnobservedTaskException
.- Si vous utilisez
Task.Wait()
, il ne sera jamais appelé car vous bloquez un résultat imminent de la tâche, par conséquent l'exception sera lancée surTask.Wait()
plutôt que sur l'événementUnobservedException
. - Appeler
GC.Collect()
manuellement est généralement une mauvaise idée, sauf si vous savez exactement ce que vous faites, d'où il est bon dans ce cas pour confirmer les choses, mais pas comme une bonne solution au problème.
Le problème
Si mes sorties d'application avant le garbage collector entre en jeu, je suis absolument 100% ne peut pas obtenir mon événement UnobservedTaskException
au feu.
Notez le code suivant:
class Program
{
static void Main(string[] args)
{
TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException;
Task.Factory.StartNew(() =>
{
Console.WriteLine("Task started.");
throw new Exception("Test Exception");
});
Thread.Sleep(1000);
//GC.Collect();
//GC.WaitForPendingFinalizers();
}
static void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
{
File.WriteAllText(@"C:\data\TestException.txt", e.Exception.ToString());
Console.WriteLine("EXCEPTION UNOBSERVED");
}
}
Aucun fichier d'exception est écrit et rien est écrit à la console. 10-15 minutes et plus peuvent s'écouler après la sortie de l'application et je ne vois toujours aucune preuve que les restes de ma demande aient été récupérés. Vous pourriez demander, eh bien pourquoi ne pas simplement recueillir à la sortie? Eh bien, mon scénario dans le monde réel est que mon interception d'exceptions s'exécute dans un service WCF hébergé dans un service Windows. Je ne peux pas piéger lorsque le service Windows est en cours d'arrêt (et donc appeler manuellement GC.Collect()
) car il n'y a pas d'événement pour autant que je puisse voir.
Où est-ce que je vais mal? Comment puis-je m'assurer que si quelque chose au fond du service WCF finit par briser mon service Windows, que j'ai une chance d'enregistrer l'exception avant que le service ne tombe?
Salut, merci pour la suggestion, même si je l'exécute déjà en dehors du débogueur.Je remarque également que vous utilisez GC.Collect(). Que se passe-t-il dans votre exemple si vous ne collectez pas manuellement? –
@Nathan: Normalement, il n'y a pas assez de pression GC pour que cela se produise dans cet exemple simple. Si le GC ne se rassemble pas, la "tâche" ne touchera pas le finaliseur et l'exception UnobservedException ne se déclenchera jamais. Cela n'arrive que lorsque le finaliseur recueille une tâche non-enracinée avec une exception. –
@Nathan: Notez que UnobservedTaskException n'empêchera pas l'application de s'arrêter dans tous les cas - vous devez gérer vos exceptions dans votre tâche, ou toujours attendre une tâche, si vous voulez empêcher cela d'arrêter une application. –