.Net Windows サービスの UnhandledException ハンドラー
-
09-06-2019 - |
質問
Windows サービスで UnhandledException ハンドラーを使用することはできますか?
通常、私はログ記録やテレホンホームなどを行うカスタムビルドの例外処理コンポーネントを使用します。このコンポーネントは 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 に厄介な例外処理配管を埋め込まなくても済むように、カスタム例外処理コンポーネントがこれをより適切に処理できる方法はありますか?
解決
わかりました。これについてもう少し調査しました。.Net で Windows サービスを作成するときは、System.ServiceProcess.ServiceBase を継承するクラスを作成します (VB では、これは .Designer.vb ファイルに隠されています)。次に、OnStart 関数と OnStop 関数をオーバーライドし、必要に応じて OnPause 関数と OnContinue 関数をオーバーライドします。これらのメソッドは基本クラス内から呼び出されるので、リフレクターを少しいじってみました。OnStart は、ServiceQueuedMainCallback と呼ばれる System.ServiceProcess.ServiceBase のメソッドによって呼び出されます。私のマシンのバージョン「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 Catch ブロックの Try 部分内から呼び出されるため、OnStart メソッド内で発生するものはすべて Try Catch ブロックによって効果的にラップされ、したがって発生する例外は技術的には処理されないと仮定します。これらは実際には ServiceQueuedMainCallback Try Catch で処理されます。したがって、少なくとも起動ルーチン中に CurrentDomain.UnhandledException が実際に発生することはありません。他の 3 つのエントリ ポイント (OnStop、OnPause、OnContinue) はすべて、同様の方法で基本クラスから呼び出されます。
したがって、例外処理コンポーネントが Start と Stop で UnhandledException をキャッチできない理由はこれで説明されていると「思います」が、OnStart で設定されたタイマーが起動時に UnhandledException を引き起こすことができない理由を説明しているかどうかはわかりません。
他のヒント
購読できるのは、 AppDomain.UnhandledException イベント. 。メッセージ ループがある場合は、 Application.ThreadException イベント.