Récupérer les exceptions non gérées de manière asynchrone

Lorsqu’une méthode async attendue lève une exception, l’exception est stockée quelque part et son lancement est retardé. Dans une application WinForms ou WPF, il utilise SynchronizationContext.Current pour signaler le lancement de l’exception. Cependant, dans une application console, par exemple, il lève l’exception sur un pool de threads et arrête l’application.

Comment puis-je empêcher les exceptions générées par une méthode async de faire tomber l’application?

MODIFIER:

Apparemment, le problème que je décris est dû au fait que j’ai des méthodes async void . Voir les commentaires.

Comment puis-je empêcher les exceptions générées par une méthode asynchrone de faire tomber l’application?

Suivez ces meilleures pratiques:

  1. Toutes les méthodes async doivent renvoyer Task ou Task sauf si elles doivent renvoyer void (gestionnaires d’événements, par exemple).
  2. À un moment donné, vous devriez await toutes les Task renvoyées par les méthodes async . La seule raison pour laquelle vous ne voudriez pas faire cela est si vous ne vous souciez plus du résultat de l’opération (par exemple, après l’avoir annulée).
  3. Si vous devez intercepter une exception d’un gestionnaire d’événement async void , saisissez-la dans le gestionnaire d’événement, exactement comme vous le feriez s’il s’agissait d’un code synchrone.

Vous pouvez trouver mon post async / await intro utile; J’y aborde également plusieurs autres meilleures pratiques.

Lorsque la méthode async est démarrée, elle capture le contexte de synchronisation actuel. Un moyen de résoudre ce problème consiste à créer votre propre contexte de synchronisation qui capture l’exception.

Le point ici est que le contexte de synchronisation envoie le rappel au pool de threads, mais avec un try / catch autour:

 public class AsyncSynchronizationContext : SynchronizationContext { public override void Send(SendOrPostCallback d, object state) { try { d(state); } catch (Exception ex) { // Put your exception handling logic here. Console.WriteLine(ex.Message); } } public override void Post(SendOrPostCallback d, object state) { try { d(state); } catch (Exception ex) { // Put your exception handling logic here. Console.WriteLine(ex.Message); } } } 

Dans la catch ci-dessus, vous pouvez mettre votre logique de traitement des exceptions.

Ensuite, sur chaque thread ( SynchronizationContext.Current [ThreadStatic] ) où vous souhaitez exécuter des méthodes async avec ce mécanisme, vous devez définir le contexte de synchronisation actuel:

 SynchronizationContext.SetSynchronizationContext(new AsyncSynchronizationContext()); 

L’exemple Main complet:

 class Program { static void Main(ssortingng[] args) { SynchronizationContext.SetSynchronizationContext(new AsyncSynchronizationContext()); ExecuteAsyncMethod(); Console.ReadKey(); } private static async void ExecuteAsyncMethod() { await AsyncMethod(); } private static async Task AsyncMethod() { throw new Exception("Exception from async"); } }