Comment puis-je créer quelque chose qui intercepte toutes les exceptions «non gérées» dans une application WinForms?

85

Jusqu'à présent, je viens de mettre un bloc try / catch autour du Application.Rundans le Program.cspoint d'entrée du programme. Cela intercepte assez bien toutes les exceptions en mode débogage, mais lorsque j'exécute le programme sans le mode débogage, les exceptions ne sont plus gérées. J'obtiens la boîte d'exception non gérée.

Je ne veux pas que ça arrive. Je veux que toutes les exceptions soient interceptées lors de l'exécution en mode non-débogage. Le programme a plusieurs threads et de préférence toutes les exceptions de ceux-ci sont interceptées par le même gestionnaire; Je souhaite enregistrer les exceptions dans la base de données. Quelqu'un at-il des conseils sur la façon de procéder?

Isaac Bolinger
la source

Réponses:

110

Jetez un œil à l'exemple de la documentation 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);
}

Vous pouvez également ne pas intercepter les exceptions lors du débogage, car cela facilite le débogage. C'est un peu un hack, mais pour cela, vous pouvez envelopper le code ci-dessus avec

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

Pour éviter d'intercepter les exceptions lors du débogage.

Can Gencer
la source
1
J'ai créé un travailleur en arrière-plan et, dans le gestionnaire d'événements dowork, j'ai intentionnellement provoqué une exception de référence nulle. Cependant, il n'a pas été intercepté par l'exception AppDomain.CurrentDomain.UnhandledException malgré les paramètres suivants: Application.ThreadException + = new System.Threading.ThreadExceptionEventHandler (Application_ThreadException); Application.SetUnhandledExceptionMode (UnhandledExceptionMode.CatchException); AppDomain.CurrentDomain.UnhandledException + = new UnhandledExceptionEventHandler (CurrentDomain_UnhandledException);
Isaac Bolinger
4
@IsaacB, le travailleur d'arrière-plan intercepte les exceptions lui-même. Vous pouvez vérifier l'exception dans le RunWorkerCompleted même, en regardant la propriété RunCompletedEventArgs.Error.
Can Gencer
1
Vous pouvez tester la gestion des exceptions pour des threads supplémentaires en plaçant cela dans le OnLoad de votre formulaire principal. new Thread (() => {throw new Exception ();}). Start ();
Can Gencer
Malheureusement, la gestion de UnhandledException n'empêchera pas l'application de se terminer :(
Nazar Grynko
7
Au lieu du hack FriendlyName.EndsWith, essayez Debugger.IsAttached qui est plus propre.
moltenform
27

Dans NET 4, certaines exceptions ne sont plus interceptées par défaut; il s'agit généralement d'exceptions qui indiquent un état corrompu (éventuellement fatal) de l'exécutable, comme une AccessViolationException.

Essayez d'utiliser la balise [HandleProcessCorruptedStateExceptions] devant votre méthode principale, par exemple

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
la source
Puis-je utiliser AppDomain.CurrentDomain.UnhandledExceptionet Application.ThreadExceptionaussi avec [HandleProcessCorruptedStateExceptions]tag?
Kiquenet
18

Un bel exemple peut être trouvé à http://www.csharp-examples.net/catching-unhandled-exceptions/ En gros, changez votre main en:

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
la source
9

Vous pouvez utiliser la bibliothèque NBug pour cela. Avec une configuration minimale comme celle-ci:

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

Vous pouvez commencer à collecter des informations sur tous les bogues non gérés dans votre application, même lorsqu'elle est déployée sur les clients. Si vous ne souhaitez pas utiliser une bibliothèque tierce, vous devez vous attacher aux événements ci-dessous:

// These two should come before enabling visual styles or running the application
AppDomain.CurrentDomain.UnhandledException += ...
Application.ThreadException += ...
...
Application.Run(new Form1());
Teoman Soygul
la source
1
Je vous en prie. Utilisez le forum de discussion du projet NBug si vous avez d'autres questions ( nbusy.com/forum/f11 ) ou utilisez la balise [nbug] ici.
Teoman Soygul
Bien entendu, vous pouvez également abonner un gestionnaire d'événements "normal" à l'événement UnhandledException. Voir msdn.microsoft.com/en-us/library/…
neo2862
Les gars sur Win7 + VS10, si je m'abonne à ces événements, l'abonnement ne fonctionne pas, à la place la boîte de dialogue standard de Windows Vista / 7 apparaît Check Online for a SolutionOu Close the Program.. etc. Mais si je ne m'abonne PAS, j'obtiens l'exception générique standard. La fenêtre. Cela se produit sur les versions Release et Debug, également essayé de définir Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);Ne change rien.
gideon
@giddy, après avoir traité les exceptions, vous devez quitter l'application avec Environment.Exit (1); si vous ne voulez pas que la fenêtre d'erreur s'affiche.
Teoman Soygul
@Teo merci pour votre réponse. Je veux que mon propre formulaire d'erreur s'affiche, puis je veux que l'application se ferme. Mais l'abonnement aux événements ne s'exécute jamais, il affiche simplement la boîte de dialogue générique Win Vista / 7 lorsqu'il rencontre des exceptions. Mais si je ne m'abonne pas, la boîte de dialogue générique d'exception non gérée .NET apparaît!
gideon