web-dev-qa-db-fra.com

Comment configurer la gestion des exceptions UnhandledException .NET dans un service Windows?

protected override void OnStart(string[] args)
{
    AppDomain.CurrentDomain.UnhandledException +=
        new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);

    Thread.Sleep(10000);

    throw new Exception();
}

void CurrentDomain_UnhandledException(object sender,
                                      UnhandledExceptionEventArgs e)
{
}

J'ai attaché un débogueur au code ci-dessus dans mon service Windows, définissant un point d'arrêt dans CurrentDomain_UnhandledException, mais il n'a jamais été atteint. L'exception apparaît en disant qu'elle n'est pas gérée, puis le service s'arrête. J'ai même essayé de mettre du code dans le gestionnaire d'événements, au cas où il serait optimisé.

N'est-ce pas la bonne façon de configurer la gestion des exceptions non gérées dans un service Windows?

48
Mike Pateras

La raison pour laquelle l'événement UnhandledException sur le AppDomain actuel ne se déclenche pas est la façon dont les services sont exécutés.

  1. L'utilisateur envoie une commande Démarrer à partir du Gestionnaire de contrôle des services Windows (SCM).
  2. La commande est reçue par l'implémentation ServiceBase du framework et envoyée à la méthode OnStart.
  3. La méthode OnStart est appelée.

Toute exception levée par OnStart est gérée dans la classe de base, enregistrée dans le journal des événements et traduite en un code d'état d'erreur renvoyé au SCM. Ainsi, l'exception ne se propage jamais au gestionnaire d'exceptions non géré d'AppDomain.

Je pense que vous trouveriez qu'une exception non gérée levée à partir d'un thread de travail dans votre service serait interceptée par le gestionnaire d'exceptions non gérées de l'AppDomain.

55
Chris Dickson

Dans un service Windows, vous ne voulez PAS exécuter beaucoup de code dans la méthode OnStart. Tout ce que vous voulez, c'est le code pour lancer votre thread de service, puis revenir.

Si vous faites cela, vous pouvez très bien gérer les exceptions qui se produisent dans votre thread de service.

par exemple.

public static void Start()
{
    AppDomain currentDomain = AppDomain.CurrentDomain;
    currentDomain.UnhandledException += new UnhandledExceptionEventHandler(currentDomain_UnhandledException);

    running = true;
    ThreadStart ts = new ThreadStart(ServiceThreadBody);
    thread = new Thread(ts);
    thread.Name = "ServiceThread";
    thread.Priority = ThreadPriority.BelowNormal;
    thread.Start();
}
9
Ian Mercer

Lorsque je travaillais sur mon propre service Windows, il s'arrêtait assez étrangement. Je pensais que c'était à cause d'une exception spontanée. En ce moment, j'attrape des exceptions non gérées sur un fichier texte. Tout d'abord, vous devez créer un nouveau fichier ServiceLog.txt sur les emplacements C en raison de la journalisation des excaptions sur le fichier texte. Avec le codage ci-dessous, j'ai obtenu toutes les exceptions non gérées avec les numéros de ligne.

using System.Security.Permissions;
using System.IO;

[SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.ControlAppDomain)]
    protected override void OnStart(string[] args)
    {   AppDomain currentDomain = AppDomain.CurrentDomain;
        currentDomain.UnhandledException += new UnhandledExceptionEventHandler(MyHandler);
        ...
        Your codes...
        ....
    }
    void MyHandler(object sender, UnhandledExceptionEventArgs args)
    {
        Exception e = (Exception)args.ExceptionObject;
        WriteToFile("Simple Service Error on: {0} " + e.Message + e.StackTrace);
    }
    private void WriteToFile(string text)
    {
        string path = "C:\\ServiceLog.txt";
        using (StreamWriter writer = new StreamWriter(path, true))
        {
            writer.WriteLine(string.Format(text, DateTime.Now.ToString("dd/MM/yyyy hh:mm:ss tt")));
            writer.Close();
        }
    }
4
Can DOGRU

Sachez que ce fil est un peu ancien, mais a pensé qu'il serait utile d'ajouter quelques commentaires basés sur l'expérience personnelle de développement de services Windows dans .NET. La meilleure approche consiste à éviter de développer autant que possible sous le Gestionnaire de contrôle des services - pour cela, vous avez besoin d'un harnais simple qui imite la façon dont les services démarrent - quelque chose qui peut créez une instance de votre classe de service (que vous avez déjà dérivée de ServiceBase) et appelez vos méthodes OnStart, OnStop, etc. Ce harnais peut être une application console ou une application Windows comme vous le souhaitez.

C'est à peu près la seule façon que j'ai trouvée de déboguer les problèmes de démarrage du service dans .NET - l'interaction entre votre code, Visual Studio et le véritable Service Control Manager rend le processus impossible autrement.

HTH.

4
SteveWilkinson

Juste curieux, qu'essayez-vous d'accomplir: éviter les pannes de service ou signaler des erreurs?

Pour les rapports, je pense que votre meilleur pari est d'ajouter des déclarations try/catch de haut niveau. Vous pouvez essayer de les enregistrer dans le journal des événements Windows et/ou dans un fichier journal.

Vous pouvez également définir la propriété ExitCode sur une valeur non nulle jusqu'à ce que vous arrêtiez le service avec succès. Si l'administrateur système démarre votre service à partir du panneau de configuration Services et que votre service s'arrête soudainement avec un code de sortie différent de zéro, Windows peut afficher un message d'erreur avec la description de l'erreur.

2
Paul Williams