Come posso creare qualcosa che catturi tutte le eccezioni "non gestite" in un'applicazione WinForms?


87

Fino ad ora, ho appena messo un blocco try / catch in tutto il Application.Runnel Program.cspunto di ingresso al programma. Questo cattura tutte le eccezioni abbastanza bene in modalità Debug, ma quando eseguo il programma senza la modalità debug, le eccezioni non vengono più gestite. Ottengo la casella delle eccezioni non gestite.

Non voglio che questo accada. Voglio che tutte le eccezioni vengano rilevate durante l'esecuzione in modalità non di debug. Il programma ha più thread e preferibilmente tutte le eccezioni vengono rilevate dallo stesso gestore; Voglio registrare le eccezioni nel DB. Qualcuno ha qualche consiglio su come farlo?

Risposte:


112

Dai un'occhiata all'esempio dalla documentazione di ThreadException :

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

Potresti anche voler non rilevare le eccezioni durante il debug, poiché questo semplifica il debug. È un po 'un trucco, ma per questo puoi avvolgere il codice sopra con

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

Per evitare di rilevare le eccezioni durante il debug.


1
Ho creato un lavoratore in background e nel gestore di eventi dowork ho causato intenzionalmente un'eccezione di riferimento nulla. Tuttavia non è stato rilevato da AppDomain.CurrentDomain.UnhandledException nonostante l'impostazione di questi: Application.ThreadException + = new System.Threading.ThreadExceptionEventHandler (Application_ThreadException); Application.SetUnhandledExceptionMode (UnhandledExceptionMode.CatchException); AppDomain.CurrentDomain.UnhandledException + = new UnhandledExceptionEventHandler (CurrentDomain_UnhandledException);
Isaac Bolinger

4
@IsaacB, il lavoratore in background rileva le eccezioni. Puoi controllare l'eccezione anche in RunWorkerCompleted, esaminando la proprietà RunCompletedEventArgs.Error.
Can Gencer

1
Puoi testare la gestione delle eccezioni per thread aggiuntivi inserendolo in OnLoad del modulo principale. new Thread (() => {lancia una nuova eccezione ();}). Start ();
Can Gencer

Sfortunatamente la gestione di UnhandledException non interromperà la chiusura dell'applicazione :(
Nazar Grynko

7
Invece dell'hack FriendlyName.EndsWith, prova Debugger.IsAttached che è più pulito.
moltenform

27

In NET 4, alcune eccezioni non vengono più rilevate per impostazione predefinita; queste tendono ad essere eccezioni che indicano uno stato danneggiato (possibilmente irreversibile) dell'eseguibile, come AccessViolationException.

Prova a utilizzare il tag [HandleProcessCorructedStateExceptions] davanti al tuo metodo principale, ad es

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

Posso usare AppDomain.CurrentDomain.UnhandledExceptione Application.ThreadExceptionanche con [HandleProcessCorruptedStateExceptions]tag?
Kiquenet

18

Un bell'esempio può essere trovato su http://www.csharp-examples.net/catching-unhandled-exceptions/ Fondamentalmente, cambia il tuo main 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");
    }

9

È possibile utilizzare la libreria NBug per questo. Con una configurazione minima come questa:

NBug.Settings.Destination1 = "Type=Mail;From=me@mycompany.com;To=bugtracker@mycompany.com;SmtpServer=smtp.mycompany.com;";
AppDomain.CurrentDomain.UnhandledException += NBug.Handler.UnhandledException;
Application.ThreadException += NBug.Handler.ThreadException;

Puoi iniziare a raccogliere informazioni su tutti i bug non gestiti nella tua applicazione, anche quando è distribuita sui client. Se non desideri utilizzare una libreria di terze parti, dovresti allegare agli eventi seguenti:

// These two should come before enabling visual styles or running the application
AppDomain.CurrentDomain.UnhandledException += ...
Application.ThreadException += ...
...
Application.Run(new Form1());

1
Prego. Usa il forum di discussione del progetto NBug se hai ulteriori domande ( nbusy.com/forum/f11 ) o usa il tag [nbug] qui.
Teoman Soygul

Ovviamente, puoi anche sottoscrivere un gestore di eventi "normale" all'evento UnhandledException. Vedere msdn.microsoft.com/en-us/library/...
neo2862

Ragazzi su Win7 + VS10, se mi iscrivo a questi eventi l'abbonamento non viene eseguito, invece viene visualizzata la normale finestra di dialogo di Windows Vista / 7 Check Online for a SolutionO Close the Program.. ecc. Ma se NON mi iscrivo, ottengo la normale eccezione generica .NET Unhandled Finestra. Ciò accade sia nelle build di rilascio che in quelle di debug, anche l'impostazione provata Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);non cambia nulla.
gideon

@giddy, dopo aver gestito le eccezioni dovresti uscire dall'applicazione con Environment.Exit (1); se non vuoi che venga visualizzata la finestra di errore.
Teoman Soygul

@Teo grazie per la tua risposta. Voglio che venga visualizzato il mio modulo di errore, quindi desidero che l'app venga chiusa. Ma l'abbonamento all'evento non viene mai eseguito, mostra solo la finestra di dialogo generica di Win Vista / 7 quando incontra eccezioni. Ma se non mi iscrivo, viene visualizzata la finestra di dialogo dell'eccezione non gestita .NET generica!
gideon
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.