Обработчик UnhandledException в службе Windows .Net
-
09-06-2019 - |
Вопрос
Можно ли использовать обработчик UnhandledException в службе Windows?
Обычно я бы использовал специально созданный компонент обработки исключений, который ведет журналирование, звонит домой и т. д.Этот компонент добавляет обработчик к System.AppDomain.CurrentDomain.UnhandledException, но, насколько я могу судить, это не дает никаких результатов для службы Windows, поэтому я получаю этот шаблон в своих 2 (или 4) точках входа в службу:
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
Есть ли способ, которым мой компонент пользовательской обработки исключений может справиться с этим лучше, чтобы мне не приходилось заполнять свой OnStart беспорядочной обработкой исключений?
Решение
Хорошо, теперь я провел еще немного исследования по этому поводу.Когда вы создаете службу Windows в .Net, вы создаете класс, который наследуется от System.ServiceProcess.ServiceBase (в VB он скрыт в файле .Designer.vb).Затем вы переопределяете функции OnStart и OnStop, а также OnPause и OnContinue, если захотите.Эти методы вызываются из базового класса, поэтому я немного поковырялся с отражателем.OnStart вызывается методом в System.ServiceProcess.ServiceBase, который называется ServiceQueuedMainCallback.Версия на моей машине «System.ServiceProcess, Version=2.0.0.0» декомпилируется следующим образом:
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
Поэтому, поскольку Me.OnStart(args) вызывается из части Try блока Try Catch, я предполагаю, что все, что происходит внутри метода OnStart, эффективно обертывается этим блоком Try Catch, и поэтому любые возникающие исключения технически не обрабатываются, поскольку на самом деле они обрабатываются в ServiceQueuedMainCallback Try Catch.Таким образом, CurrentDomain.UnhandledException на самом деле никогда не происходит, по крайней мере, во время процедуры запуска.Остальные три точки входа (OnStop, OnPause и OnContinue) вызываются из базового класса аналогичным образом.
Поэтому я «думаю», что это объясняет, почему мой компонент обработки исключений не может перехватить UnhandledException при запуске и остановке, но я не уверен, объясняет ли это, почему таймеры, настроенные в OnStart, не могут вызвать UnhandledException при срабатывании.
Другие советы
Вы можете подписаться на Событие AppDomain.UnhandledException.Если у вас есть цикл сообщений, вы можете привязать его к Событие Application.ThreadException.