web-dev-qa-db-ja.com

Windowsサービスで.NET UnhandledException処理を設定するにはどうすればよいですか?

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)
{
}

Windowsサービスの上記のコードにデバッガーを接続し、CurrentDomain_UnhandledExceptionにブレークポイントを設定しましたが、ヒットしませんでした。例外が処理されないと表示され、サービスが停止します。それが最適化されてしまう場合に備えて、イベントハンドラーにコードを追加してみました。

これは、Windowsサービスで未処理の例外処理を設定する適切な方法ではありませんか?

48
Mike Pateras

現在のAppDomainのUnhandledExceptionイベントが発生しない理由は、サービスの実行方法です。

  1. ユーザーは、Windowsサービスコントロールマネージャー(SCM)からStartコマンドを送信します。
  2. コマンドは、フレームワークのServiceBase実装によって受信され、OnStartメソッドにディスパッチされます。
  3. OnStartメソッドが呼び出されます。

OnStartによってスローされる例外は基本クラスで処理されます、イベントログに記録され、SCMに返されるエラーステータスコードに変換されます。そのため、例外がAppDomainの未処理の例外ハンドラーに伝達されることはありません。

サービスのワーカースレッドからスローされた未処理の例外wouldは、AppDomainの未処理の例外ハンドラーによってキャッチされると思います。

55
Chris Dickson

Windowsサービスでは、OnStartメソッドで多くのコードを実行する必要はありません。必要なのは、サービススレッドを起動して戻るコードだけです。

これを行うと、サービススレッドで発生する例外を問題なく処理できます。

例えば.

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

私が自分のWindowsサービスで作業していたとき、それはそれ自体が奇妙に止まっていました。勝手な例外のせいだと思った。現時点では、テキストファイルで手につかない例外をキャッチしています。まず、テキストファイルの説明のログを記録するため、Cの場所に新しいファイルServiceLog.txtを作成する必要があります。以下のコーディングで、私はそれらの行番号を含むすべての例外を手に入れました。

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

このスレッドは少し古いことを知っていますが、.NETでWindowsサービスを開発した個人的な経験に基づいてコメントを追加すると便利だと思いました。 最善のアプローチは、サービスコントロールマネージャーでの開発をできるだけ避けることです-これには、サービスの開始方法を模倣するシンプルなハーネスが必要です-できるもの(ServiceBaseから既に派生した)サービスクラスのインスタンスを作成し、OnStart、OnStopなどのメソッドを呼び出します。このハーネスは、必要に応じてコンソールアプリまたはWindowsアプリにすることができます。

これは、.NETでサービスの起動に関する問題をデバッグするために私が見つけたほとんど唯一の方法です。コード、Visual Studio、および実際のサービスコントロールマネージャー間の相互作用により、プロセスが不可能になります。

HTH。

4
SteveWilkinson

好奇心旺盛ですが、サービスのクラッシュを回避したり、エラーを報告したりして、何を達成しようとしているのですか?

レポートについては、トップレベルのtry/catchステートメントを追加するのが最善の策だと思います。それらをWindowsイベントログまたはログファイル、あるいはその両方に記録してみることができます。

サービスを正常に停止するまで、 ExitCode プロパティをゼロ以外の値に設定することもできます。システム管理者がサービスコントロールパネルからサービスを開始し、サービスがゼロ以外の終了コードで突然停止した場合、Windowsはエラーの説明とともにエラーメッセージを表示できます。

2
Paul Williams