.NET - Quel est le meilleur moyen d'implémenter un «gestionnaire d'interception de toutes les exceptions»

StackOverflow https://stackoverflow.com/questions/219594

Question

Je me demande quel est le meilleur moyen d'avoir un "si tout le reste échoue à l'attraper".

Je veux dire, vous manipulez autant d'exceptions que possible dans votre application, mais il y a toujours des bugs, alors j'ai besoin de quelque chose qui intercepte toutes les exceptions non gérées afin que je puisse collecter des informations et les stocker les dans une base de données ou les soumettre à un service Web.

L'événement AppDomain.CurrentDomain.UnhandledException capture-t-il tout? Même si l'application est multithread?

Remarque secondaire: Windows Vista expose les fonctions de l'API native permettant à toute application se rétablir après un crash ... je ne peux pas penser au nom maintenant ... mais je préfère ne pas utilisez-le, car beaucoup de nos utilisateurs utilisent encore Windows XP.

Était-ce utile?

La solution

Je viens de jouer avec le comportement UnhandledException de AppDomain, (C’est la dernière étape à laquelle l’exception non gérée est enregistrée)

Oui, après le traitement des gestionnaires d’événements, votre application sera fermée et le méchant programme "... arrêté de travailler avec la boîte de dialogue" " montré.

:) Vous encore pouvez éviter cela.

Départ:

class Program
{
    void Run()
    {
        AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);

        Console.WriteLine("Press enter to exit.");

        do
        {
            (new Thread(delegate()
            {
                throw new ArgumentException("ha-ha");
            })).Start();

        } while (Console.ReadLine().Trim().ToLowerInvariant() == "x");


        Console.WriteLine("last good-bye");
    }

    int r = 0;

    void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
    {
        Interlocked.Increment(ref r);
        Console.WriteLine("handled. {0}", r);
        Console.WriteLine("Terminating " + e.IsTerminating.ToString());

        Thread.CurrentThread.IsBackground = true;
        Thread.CurrentThread.Name = "Dead thread";            

        while (true)
            Thread.Sleep(TimeSpan.FromHours(1));
        //Process.GetCurrentProcess().Kill();
    }

    static void Main(string[] args)
    {
        Console.WriteLine("...");
        (new Program()).Run();
    }
}

P.S. Traitez les exceptions non gérées pour Application.ThreadException (WinForms) ou DispatcherUnhandledException (WPF) au niveau supérieur.

Autres conseils

Dans ASP.NET, vous utilisez la fonction Application_Error du fichier Global.asax .

Dans WinForms, vous utilisez MyApplication_UnhandledException dans le fichier ApplicationEvents

.

Ces deux fonctions sont appelées si une exception non gérée se produit dans votre code. Vous pouvez enregistrer l’exception et présenter un gentil message à l’utilisateur à partir de ces fonctions.

Pour les applications Winform, en plus de AppDomain.CurrentDomain.UnhandledException, j'utilise également Application.ThreadException et Application.SetUnhandledExceptionMode (avec UnhandledExceptionMode.CatchException). Cette combinaison semble tout attraper.

Sur le fil principal, vous avez les options suivantes:

Pour les autres discussions:

  • Les threads secondaires n'ont pas d'exceptions non gérées; utilisez SafeThread
  • Discussions des travailleurs: (timer, threadpool), il n’existe aucun filet de sécurité!

N'oubliez pas que ces événements ne traitent pas les exceptions, ils les signalent à l'application - souvent lorsqu'il est trop tard pour faire quelque chose d'utile / sain. à leur sujet

La journalisation des exceptions est une bonne chose, mais la surveillance des applications est meilleure; -)

Avertissement: je suis l'auteur de l'article SafeThread .

Pour WinForms, n'oubliez pas de joindre également à l'événement d'exception non géré du thread actuel (surtout si vous utilisez le multi-threading).

Quelques liens sur les meilleures pratiques ici et ici et ici (probablement le meilleur article sur la gestion des exceptions pour .net)

.

Il existe également un élément intéressant appelé ELMAH , qui enregistre les erreurs ASP.NET se produire dans une application Web. Je sais que vous parlez d'une solution Winform App, mais j’ai pensé que cela pourrait être bénéfique pour tous ceux qui ont besoin de ce type d’application sur une application Web. Nous l’utilisons là où je travaille et cela a été très utile pour le débogage (surtout sur les serveurs de production!)

Voici quelques fonctionnalités dont il dispose (tiré de la page):

  
      
  • Journalisation de presque toutes les exceptions non gérées.
  •   
  • Une page Web permettant d'afficher à distance l'intégralité du journal des exceptions recodées.
  •   
  • Une page Web permettant d'afficher à distance les détails complets de l'une des exceptions consignées.
  •   
  • Dans de nombreux cas, vous pouvez consulter l’écran jaune de la mort original qui   ASP.NET généré pour une donnée   exception, même avec le mode customErrors   désactivé.
  •   
  • Une notification par courrier électronique de chaque erreur au moment où elle se produit.
  •   
  • Flux RSS des 15 dernières erreurs du journal.
  •   
  • Un certain nombre d'implémentations de stockage de sauvegarde pour le journal, notamment:   en mémoire, Microsoft SQL Server et   plusieurs contributions de la communauté.
  •   

Vous pouvez surveiller la plupart des exceptions dans ce gestionnaire même dans les applications multithreads, mais .NET (à partir de 2.0) ne vous permettra pas d'annuler les exceptions non gérées, sauf si vous activez le mode de compatibilité 1.1. Lorsque cela se produit, AppDomain sera arrêté quoi qu'il arrive. Le mieux que vous puissiez faire est de lancer l'application dans un AppDomain différent afin de pouvoir gérer cette exception et créer un nouvel AppDomain pour redémarrer l'application.

J'utilise l'approche suivante, qui fonctionne et réduit considérablement la quantité de code (mais je ne suis pas sûr s'il existe une meilleure façon ni quels sont les pièges de celle-ci. Chaque fois que vous appelez: Je pense que donner des inconvénients serait assez poli pour clarifier leurs actions; )

try 
{
    CallTheCodeThatMightThrowException()
 }
catch (Exception ex)
{
    System.Diagnostics.StackTrace st = new System.Diagnostics.StackTrace ();
    Utils.ErrorHandler.Trap ( ref objUser, st, ex );
} //eof catch

Et voici le code ErrorHandler: Pour être clair: objUser - l’objet modélisant les utilisateurs (vous pouvez obtenir des informations telles que le nom de domaine, le département, la région, etc. à des fins de journalisation. Enregistreur ILog - est l'objet de journalisation - par exemple. celui qui effectue les activités de journalisation StackTrace st - l'objet StackTrace vous donnant des informations de débogage pour votre application

using System;
using log4net; //or another logging platform

namespace GenApp.Utils
{
  public class ErrorHandler
  {
    public static void Trap ( Bo.User objUser, ILog logger, System.Diagnostics.StackTrace st, Exception ex )
    {
      if (ex is NullReferenceException)
      { 
      //do stuff for this ex type
      } //eof if

      if (ex is System.InvalidOperationException) 
      {
        //do stuff for this ex type
      } //eof if

      if (ex is System.IndexOutOfRangeException) 
      {
        //do stuff for this ex type
      } //eof if

      if (ex is System.Data.SqlClient.SqlException)
      {
        //do stuff for this ex type
      } //eof if

      if (ex is System.FormatException)
      {
        //do stuff for this ex type
      } //eof if

      if (ex is Exception)
      {
        //do stuff for this ex type
      } //eof catch

    } //eof method 

  }//eof class 
} //eof namesp

Dans une application à interface graphique gérée, par défaut, les exceptions provenant du fil de l'interface graphique sont gérées par tout ce qui est affecté à Application.ThreadException.

Les exceptions qui proviennent des autres threads sont gérées par AppDomain.CurrentDomain.UnhandledException.

Si vous souhaitez que vos exceptions de thread d'interface graphique fonctionnent de la même manière que celles qui ne le sont pas, afin qu'elles soient gérées par AppDomain.CurrentDomain.UnhandledException, procédez comme suit:

Application.SetUnhandledExceptionMode(UnhandledExceptionMode.ThrowException);

Un avantage à intercepter les exceptions de thread d'interface graphique à l'aide de ThreadException est que vous pouvez donner à l'utilisation la possibilité de laisser l'application continuer. Pour vous assurer qu'aucun fichier de configuration ne remplace le comportement par défaut, vous pouvez appeler:

Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);

Vous êtes toujours vulnérable aux exceptions provenant de dll natives mal comportées. Si une dll native installe son propre gestionnaire à l'aide de Win32 SetUnhandledExceptionFilter, elle est supposée enregistrer le pointeur sur le filtre précédent et l'appeler également. S'il ne le fait pas, votre gestionnaire ne sera pas appelé.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top