Gestionnaire UnhandledException dans un service Windows .Net
-
09-06-2019 - |
Question
Est-il possible d'utiliser un gestionnaire UnhandledException dans un service Windows ?
Normalement, j'utiliserais un composant de gestion des exceptions personnalisé qui effectue la journalisation, le téléphone à la maison, etc.Ce composant ajoute un gestionnaire à System.AppDomain.CurrentDomain.UnhandledException mais pour autant que je sache, cela ne permet pas de gagner un service Windows, je me retrouve donc avec ce modèle dans mes 2 (ou 4) points d'entrée de service :
Protected Overrides Sub OnStart(ByVal args() As String)
' Add code here to start your service. This method should set things
' in motion so your service can do its work.
Try
MyServiceComponent.Start()
Catch ex As Exception
'call into our exception handler
MyExceptionHandlingComponent.ManuallyHandleException (ex)
'zero is the default ExitCode for a successfull exit, so if we set it to non-zero
ExitCode = -1
'So, we use Environment.Exit, it seems to be the most appropriate thing to use
'we pass an exit code here as well, just in case.
System.Environment.Exit(-1)
End Try
End Sub
Existe-t-il un moyen pour mon composant de gestion des exceptions personnalisées de mieux gérer cela afin que je n'aie pas à remplir mon OnStart avec une plomberie de gestion des exceptions désordonnée ?
La solution
Ok, j'ai fait un peu plus de recherches à ce sujet maintenant.Lorsque vous créez un service Windows dans .Net, vous créez une classe qui hérite de System.ServiceProcess.ServiceBase (en VB, elle est cachée dans le fichier .Designer.vb).Vous remplacez ensuite les fonctions OnStart et OnStop, ainsi que OnPause et OnContinue si vous le souhaitez.Ces méthodes sont invoquées depuis la classe de base, j'ai donc fouillé un peu avec le réflecteur.OnStart est invoqué par une méthode dans System.ServiceProcess.ServiceBase appelée ServiceQueuedMainCallback.La version sur ma machine "System.ServiceProcess, Version=2.0.0.0" se décompile comme ceci :
Private Sub ServiceQueuedMainCallback(ByVal state As Object)
Dim args As String() = DirectCast(state, String())
Try
Me.OnStart(args)
Me.WriteEventLogEntry(Res.GetString("StartSuccessful"))
Me.status.checkPoint = 0
Me.status.waitHint = 0
Me.status.currentState = 4
Catch exception As Exception
Me.WriteEventLogEntry(Res.GetString("StartFailed", New Object() { exception.ToString }), EventLogEntryType.Error)
Me.status.currentState = 1
Catch obj1 As Object
Me.WriteEventLogEntry(Res.GetString("StartFailed", New Object() { String.Empty }), EventLogEntryType.Error)
Me.status.currentState = 1
End Try
Me.startCompletedSignal.Set
End Sub
Donc, parce que Me.OnStart(args) est appelé depuis la partie Try d'un bloc Try Catch, je suppose que tout ce qui se passe dans la méthode OnStart est effectivement encapsulé par ce bloc Try Catch et donc toutes les exceptions qui se produisent ne sont pas techniquement gérées comme ils sont en fait gérés dans ServiceQueuedMainCallback Try Catch.Ainsi, CurrentDomain.UnhandledException ne se produit jamais, au moins pendant la routine de démarrage.Les 3 autres points d'entrée (OnStop, OnPause et OnContinue) sont tous appelés depuis la classe de base de la même manière.
Donc, je « pense » que cela explique pourquoi mon composant de gestion des exceptions ne peut pas intercepter UnhandledException au démarrage et à l'arrêt, mais je ne sais pas si cela explique pourquoi les minuteries configurées dans OnStart ne peuvent pas provoquer une UnhandledException lorsqu'elles se déclenchent.
Autres conseils
Vous pouvez vous abonner au Événement AppDomain.UnhandledException.Si vous disposez d'une boucle de messages, vous pouvez la lier au Événement Application.ThreadException.