web-dev-qa-db-fra.com

Gestionnaire d'exception globale .NET dans l'application console

Question: Je veux définir un gestionnaire d'exception global pour les exceptions non gérées dans mon application console. Dans asp.net, on peut en définir un dans global.asax, et dans Windows applications/services, on peut définir comme suit

AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.UnhandledException += new UnhandledExceptionEventHandler(MyExceptionHandler);

Mais comment définir un gestionnaire d'exception global pour une application console?
currentDomain semble ne pas fonctionner (.NET 2.0)?

Edit:

Argh, erreur stupide.
Dans VB.NET, il est nécessaire d’ajouter le mot-clé "AddHandler" devant CurrentDomain, sinon on ne voit pas l’événement UnhandledException dans IntelliSense ...
En effet, les compilateurs VB.NET et C # traitent différemment la gestion des événements.

183
Stefan Steiger

Non, c'est la bonne façon de le faire. Cela a fonctionné exactement comme il se doit, quelque chose sur lequel vous pouvez travailler peut-être:

using System;

class Program {
    static void Main(string[] args) {
        System.AppDomain.CurrentDomain.UnhandledException += UnhandledExceptionTrapper;
        throw new Exception("Kaboom");
    }

    static void UnhandledExceptionTrapper(object sender, UnhandledExceptionEventArgs e) {
        Console.WriteLine(e.ExceptionObject.ToString());
        Console.WriteLine("Press Enter to continue");
        Console.ReadLine();
        Environment.Exit(1);
    }
}

N'oubliez pas que vous ne pouvez pas intercepter de cette manière les exceptions de charge de type et de fichier générées par la gigue. Ils se produisent avant que votre méthode Main () ne commence à s'exécuter. Catching ceux-ci nécessite de retarder la gigue, déplacez le code à risque dans une autre méthode et appliquez-lui l'attribut [MethodImpl (MethodImplOptions.NoInlining)].

263
Hans Passant

Si vous avez une application mono-thread, vous pouvez utiliser un simple try/catch dans la fonction Main. Toutefois, cela ne couvre pas les exceptions qui peuvent être émises en dehors de la fonction Main, sur d'autres threads, par exemple (comme indiqué dans d'autres commentaires). Ce code montre comment une exception peut provoquer la fermeture de l'application même si vous avez essayé de la gérer dans Main (notez comment le programme se ferme normalement si vous appuyez sur Entrée et autorisez l'application à se fermer normalement avant que l'exception ne se produise, mais si vous le laissez s'exécuter , ça se termine assez malheureusement):

static bool exiting = false;

static void Main(string[] args)
{
   try
   {
      System.Threading.Thread demo = new System.Threading.Thread(DemoThread);
      demo.Start();
      Console.ReadLine();
      exiting = true;
   }
   catch (Exception ex)
   {
      Console.WriteLine("Caught an exception");
   }
}

static void DemoThread()
{
   for(int i = 5; i >= 0; i--)
   {
      Console.Write("24/{0} =", i);
      Console.Out.Flush();
      Console.WriteLine("{0}", 24 / i);
      System.Threading.Thread.Sleep(1000);
      if (exiting) return;
   }
}

Vous pouvez recevoir une notification du moment où un autre thread lève une exception pour effectuer un nettoyage avant la fermeture de l'application, mais pour autant que je sache, vous ne pouvez pas, à partir d'une application console, forcer l'application à continuer de s'exécuter si vous ne gérez pas l'exception. sur le fil à partir duquel elle est lancée sans utiliser d’obscurses options de compatibilité pour que l’application se comporte comme elle le ferait avec .NET 1.x. Ce code montre comment le thread principal peut être averti des exceptions provenant d'autres threads, mais finira toujours mal:

static bool exiting = false;

static void Main(string[] args)
{
   try
   {
      System.Threading.Thread demo = new System.Threading.Thread(DemoThread);
      AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
      demo.Start();
      Console.ReadLine();
      exiting = true;
   }
   catch (Exception ex)
   {
      Console.WriteLine("Caught an exception");
   }
}

static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
   Console.WriteLine("Notified of a thread exception... application is terminating.");
}

static void DemoThread()
{
   for(int i = 5; i >= 0; i--)
   {
      Console.Write("24/{0} =", i);
      Console.Out.Flush();
      Console.WriteLine("{0}", 24 / i);
      System.Threading.Thread.Sleep(1000);
      if (exiting) return;
   }
}

Donc, à mon avis, le moyen le plus propre de le gérer dans une application console est de s'assurer que chaque thread a un gestionnaire d'exceptions au niveau racine:

static bool exiting = false;

static void Main(string[] args)
{
   try
   {
      System.Threading.Thread demo = new System.Threading.Thread(DemoThread);
      demo.Start();
      Console.ReadLine();
      exiting = true;
   }
   catch (Exception ex)
   {
      Console.WriteLine("Caught an exception");
   }
}

static void DemoThread()
{
   try
   {
      for (int i = 5; i >= 0; i--)
      {
         Console.Write("24/{0} =", i);
         Console.Out.Flush();
         Console.WriteLine("{0}", 24 / i);
         System.Threading.Thread.Sleep(1000);
         if (exiting) return;
      }
   }
   catch (Exception ex)
   {
      Console.WriteLine("Caught an exception on the other thread");
   }
}
23
BlueMonkMN

Vous devez également gérer les exceptions des threads:

static void Main(string[] args) {
Application.ThreadException += MYThreadHandler;
}

private void MYThreadHandler(object sender, Threading.ThreadExceptionEventArgs e)
{
    Console.WriteLine(e.Exception.StackTrace);
}

Whoop, désolé, c'était pour les winforms, pour tous les threads que vous utilisez dans une application console, vous devrez inclure un bloc try/catch. Les threads d'arrière-plan qui rencontrent des exceptions non gérées ne provoquent pas la fin de l'application.

12
BlackICE