.NET Global-Ausnahmehandler in der Konsolenanwendung

Frage: Ich möchte einen globalen Ausnahme-Handler für nicht behandelte Ausnahmen in meiner Konsolenanwendung definieren. In asp.net kann man einen in global.asax definieren, und in Windows-Anwendungen / Diensten kann man wie folgt definieren

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

Aber wie kann ich einen globalen Ausnahmehandler für eine Konsolenanwendung definieren?
currentDomain scheint nicht zu funktionieren (.NET 2.0)?

Bearbeiten:

Argh, dummer Fehler.
In VB.NET muss vor “currentDomain” das Schlüsselwort “AddHandler” hinzugefügt werden, andernfalls wird das Ereignis “UnhandledException” in IntelliSense nicht angezeigt.
Das liegt daran, dass die VB.NET- und C # -Compiler die Ereignisbehandlung unterschiedlich behandeln.

   

Nein, das ist der richtige Weg. Dies funktioniert genau so, wie es sollte, etwas woran man vielleicht arbeiten kann:

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

Denken Sie daran, dass Sie vom Jitter erzeugte Typ- und Dateiladeausnahmen auf diese Weise nicht abfangen können. Sie treten auf, bevor Ihre Main () -Methode gestartet wird. Um diese zu fangen, müssen Sie den Jitter verzögern, den risikoreichen Code in eine andere Methode verschieben und das Attribut [MethodImpl (MethodImplOptions.NoInlining)] darauf anwenden.

Wenn Sie eine single-threaded Anwendung haben, können Sie eine einfache try / catch in der Main-function verwenden, dies deckt jedoch keine Exceptions ab, die außerhalb der Main-function, zum Beispiel in anderen Threads, geworfen werden können Bemerkungen). Dieser Code zeigt, wie eine Ausnahme dazu führen kann, dass die Anwendung beendet wird, obwohl Sie versucht haben, sie in Main zu behandeln (beachten Sie, dass das Programm ordnungsgemäß beendet wird, wenn Sie die Eingabetaste drücken und die Anwendung ordnungsgemäß beenden, bevor die Ausnahme ausgeführt wird es endet ziemlich unglücklich):

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

Sie können Benachrichtigungen darüber erhalten, wenn ein anderer Thread vor dem Beenden der Anwendung eine Bereinigung austriggers, um eine Bereinigung durchzuführen. Aber soweit ich das beurteilen kann, können Sie die Anwendung nicht von einer Konsolenanwendung aus fortsetzen, wenn Sie die Ausnahme nicht behandeln auf den Thread, aus dem es geworfen wird, ohne einige obskure Kompatibilitätsoptionen zu verwenden, damit sich die Anwendung so verhält, als ob sie mit .NET 1.x hätte. Dieser Code demonstriert, wie der Hauptthread über Ausnahmen benachrichtigt werden kann, die von anderen Threads stammen, aber trotzdem unglücklicherweise beendet wird:

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

Meiner Meinung nach ist der sauberste Weg, um es in einer Konsolenanwendung zu handhaben, sicherzustellen, dass jeder Thread einen Exception-Handler auf der Stammebene hat:

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

Sie müssen auch Ausnahmen von Threads behandeln:

 static void Main(string[] args) { Application.ThreadException += MYThreadHandler; } private void MYThreadHandler(object sender, Threading.ThreadExceptionEventArgs e) { Console.WriteLine(e.Exception.StackTrace); } 

Whoop, sorry, das war für winforms, für alle Threads, die Sie in einer Konsolenanwendung verwenden, müssen Sie in einen try / catch-Block einschließen. Hintergrundthreads, die auf nicht behandelte Ausnahmen stoßen, führen nicht dazu, dass die Anwendung beendet wird.

Was Sie versuchen, sollte gemäß dem MSDN-Dokument für .Net 2.0 funktionieren. Sie können auch einen Versuch / Fang direkt im Hauptbereich um Ihren Einstiegspunkt für die Konsolen-App versuchen.

 static void Main(string[] args) { try { // Start Working } catch (Exception ex) { // Output/Log Exception } finally { // Clean Up If Needed } } 

Und jetzt wird dein Fang mit allem umgehen, was nicht gefangen ist ( im Hauptthread ). Es kann graziös sein und sogar neu starten, wo es war, wenn Sie möchten, oder Sie können einfach die App sterben lassen und die Ausnahme protokollieren. Sie würden schließlich ein hinzufügen, wenn Sie aufräumen wollten. Jeder Thread benötigt eine eigene High-Level-Exception-Behandlung ähnlich der Main.

Bearbeitet, um den Punkt zu Threads zu klären, auf den BlueMonkMN hingewiesen hat und der in seiner Antwort ausführlich dargestellt ist.