Wie kann ich etwas erstellen, das alle "nicht behandelten" Ausnahmen in einer WinForms-Anwendung abfängt?

84

Bis jetzt habe ich nur einen Try / Catch-Block um Application.Runden Program.csEinstiegspunkt des Programms gelegt. Dadurch werden alle Ausnahmen im Debug-Modus gut genug erfasst, aber wenn ich das Programm ohne den Debug-Modus ausführe, werden Ausnahmen nicht mehr behandelt. Ich bekomme die unbehandelte Ausnahmebox.

Ich möchte nicht, dass das passiert. Ich möchte, dass alle Ausnahmen abgefangen werden, wenn sie im Nicht-Debug-Modus ausgeführt werden. Das Programm hat mehrere Threads und vorzugsweise werden alle Ausnahmen von demselben Handler abgefangen. Ich möchte Ausnahmen in der Datenbank protokollieren. Hat jemand einen Rat, wie das geht?

Isaac Bolinger
quelle

Antworten:

110

Schauen Sie sich das Beispiel aus der ThreadException-Dokumentation an :

public static void Main(string[] args)
{
   // Add the event handler for handling UI thread exceptions to the event.
    Application.ThreadException += new     
  ThreadExceptionEventHandler(ErrorHandlerForm.Form1_UIThreadException);

  // Set the unhandled exception mode to force all Windows Forms errors
  // to go through our handler.
  Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);

  // Add the event handler for handling non-UI thread exceptions to the event. 
  AppDomain.CurrentDomain.UnhandledException += new       
  UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
}

Möglicherweise möchten Sie beim Debuggen auch keine Ausnahmen abfangen, da dies das Debuggen erleichtert. Es ist ein bisschen wie ein Hack, aber dafür können Sie den obigen Code mit umschließen

 if (!AppDomain.CurrentDomain.FriendlyName.EndsWith("vshost.exe")) { ... }

Um zu verhindern, dass beim Debuggen die Ausnahmen abgefangen werden.

Kann Gencer
quelle
1
Ich habe einen Hintergrundarbeiter erstellt und im Dowork-Ereignishandler absichtlich eine Nullreferenzausnahme verursacht. Es wurde jedoch nicht von der AppDomain.CurrentDomain.UnhandledException abgefangen, obwohl Folgendes festgelegt wurde: Application.ThreadException + = neuer System.Threading.ThreadExceptionEventHandler (Application_ThreadException); Application.SetUnhandledExceptionMode (UnhandledExceptionMode.CatchException); AppDomain.CurrentDomain.UnhandledException + = neuer UnhandledExceptionEventHandler (CurrentDomain_UnhandledException);
Isaac Bolinger
4
@IsaacB, Hintergrundarbeiter fängt Ausnahmen selbst ab. Sie können die Ausnahme sogar in RunWorkerCompleted überprüfen, indem Sie sich die RunCompletedEventArgs.Error-Eigenschaft ansehen.
Kann Gencer
1
Sie können die Ausnahmebehandlung für zusätzliche Threads testen, indem Sie diese in das OnLoad Ihres Hauptformulars einfügen. neuer Thread (() => {neue Ausnahme auslösen ();}). Start ();
Kann Gencer
Leider verhindert die Behandlung von UnhandledException nicht, dass die Anwendung beendet wird :(
Nazar Grynko
7
Versuchen Sie anstelle des Hack "FriendlyName.EndsWith" Debugger.IsAttached, das sauberer ist.
geschmolzene Form
27

In NET 4 werden bestimmte Ausnahmen nicht mehr standardmäßig erfasst. Dies sind in der Regel Ausnahmen, die auf einen (möglicherweise schwerwiegenden) beschädigten Status der ausführbaren Datei hinweisen, z. B. eine AccessViolationException.

Versuchen Sie, das Tag [HandleProcessCorruptedStateExceptions] vor Ihrer Hauptmethode zu verwenden, z

using System.Runtime.ExceptionServices.HandleProcessCorruptedStateExceptions

[HandleProcessCorruptedStateExceptions]
public static int Main()
{
    try
    {
        // Catch any exceptions leaking out of the program
        CallMainProgramLoop();
    }
    catch (Exception e) // We could be catching anything here
    {
        System.Console.WriteLine(e.Message);
        return 1;
    }
    return 0;
  } 
Carlos P.
quelle
Kann ich AppDomain.CurrentDomain.UnhandledExceptionund Application.ThreadExceptionauch mit [HandleProcessCorruptedStateExceptions]Tag verwenden?
Kiquenet
18

Ein schönes Beispiel finden Sie unter http://www.csharp-examples.net/catching-unhandled-exceptions/ . Ändern Sie grundsätzlich Ihre Hauptleitung in:

static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);

        Application.ThreadException += new ThreadExceptionEventHandler(Application_ThreadException);
        Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
        AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);

        Application.Run(new Form1());
    }

    static void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
    {
        MessageBox.Show(e.Exception.Message, "Unhandled Thread Exception");
    }

    static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
    {
        MessageBox.Show((e.ExceptionObject as Exception).Message, "Unhandled UI Exception");
    }
Seb
quelle
9

Sie können dafür die NBug- Bibliothek verwenden. Mit minimalem Setup wie folgt:

NBug.Settings.Destination1 = "Type=Mail;[email protected];[email protected];SmtpServer=smtp.mycompany.com;";
AppDomain.CurrentDomain.UnhandledException += NBug.Handler.UnhandledException;
Application.ThreadException += NBug.Handler.ThreadException;

Sie können Informationen zu allen nicht behandelten Fehlern in Ihrer Anwendung sammeln, auch wenn diese auf den Clients bereitgestellt werden. Wenn Sie keine Bibliothek eines Drittanbieters verwenden möchten, sollten Sie folgende Ereignisse anhängen:

// These two should come before enabling visual styles or running the application
AppDomain.CurrentDomain.UnhandledException += ...
Application.ThreadException += ...
...
Application.Run(new Form1());
Teoman Soygul
quelle
1
Bitte. Verwenden Sie das NBug-Projektdiskussionsforum, wenn Sie weitere Fragen haben ( nbusy.com/forum/f11 ), oder verwenden Sie hier das Tag [nbug].
Teoman Soygul
Natürlich können Sie das UnhandledException-Ereignis auch mit einem "regulären" Ereignishandler abonnieren. Siehe msdn.microsoft.com/en-us/library/…
neo2862
Leute unter Win7 + VS10, wenn ich diese Ereignisse abonniere, wird das Abonnement nicht ausgeführt, stattdessen wird das reguläre Windows Vista / 7-Dialogfeld angezeigt. Check Online for a SolutionOder Close the Program... usw. Wenn ich mich jedoch NICHT anmelde, erhalte ich die reguläre generische .NET-Ausnahme Fenster. Dies geschieht sowohl bei Release- als auch bei Debug-Builds. Außerdem wurde versucht, die Einstellung Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);ändert nichts.
Gideon
@giddy, nachdem Sie die Ausnahmen behandelt haben, sollten Sie die Anwendung mit Environment.Exit (1) beenden. Wenn Sie nicht möchten, dass das Fehlerfenster angezeigt wird.
Teoman Soygul
@Teo danke für deine Antwort. Ich möchte, dass mein eigenes Fehlerformular angezeigt wird, und dann möchte ich, dass die App beendet wird. Das Ereignisabonnement wird jedoch nie ausgeführt. Es zeigt nur den allgemeinen Win Vista / 7-Dialog an, wenn Ausnahmen auftreten. Wenn ich mich jedoch nicht anmelde, wird das generische Dialogfeld für nicht behandelte .NET-Ausnahmen angezeigt!
Gideon