web-dev-qa-db-ja.com

Windowsサービスをどのようにデバッグしますか?

このトピックに関するMSDNの記事を読みました。引用するには:

サービスはVisual Studio内からではなく、Services Control Managerのコンテキスト内から実行する必要があるため、サービスのデバッグは他のVisual Studioアプリケーションタイプのデバッグほど簡単ではありません。サービスをデバッグするには、サービスを開始してから、実行中のプロセスにデバッガーを接続する必要があります。その後、Visual Studioのすべての標準デバッグ機能を使用してアプリケーションをデバッグできます。

今、私の問題は私のサービスがそもそも開始できないことです。最初にクラッシュし、言います:

MyServiceName.exe [3596]で未処理の例外(System.Runtime.InteropServices.COMException)が発生しました)

デバッグすることをお勧めします(デバッガインスタンスを選択すると、すぐにクラッシュします)。それからそれは言う

ローカルコンピューターでMyServiceNameサービスを開始できませんでした。エラー1053:サービスは、開始要求または制御要求にタイムリーに応答しませんでした

それでは、サービスが開始されない理由をどのように調査/デバッグできますか?問題は、サービスが行うことを正確に行うコンソールアプリケーションを作成し、正常に動作することです。 (つまり、OnStart()メソッドとメインループのコンテンツをmainにコピーしただけです)。

任意の助けをいただければ幸いです。

サービスは、相互運用を多用するC#で記述されています。 VS2008を使用しています

47
Armen Tsirunyan

パラメーターを使用して、アプリケーションにサービスとして起動するか通常のアプリとして起動するかを決定させることができます(つまり、この場合、フォームを表示するか、サービスを起動します)。

_static void Main(string[] args)
{
    if ((1 == args.Length) && ("-runAsApp" == args[0]))
    {
        Application.Run(new application_form());
    }
    else
    {
        System.ServiceProcess.ServiceBase[] ServicesToRun;
        ServicesToRun = new ServiceBase[] { new MyService() };
        System.ServiceProcess.ServiceBase.Run(ServicesToRun);
    }
}
_

パラメーター「-runAsApp」を渡すと、アプリケーションを通常どおりデバッグできます。SCMはこのパラメーターを渡さないため、コード変更なしでサービスとして使用することもできます(ServiceBaseから派生した場合)

編集:

Windowsサービスとのもう1つの違いはIDです(これはInterOpで特に重要になる可能性があります)。「アプリ」モードとサービスモードで同じIDでテストしていることを確認する必要があります。

そのためには、アプリモードでなりすまし(C#ラッパーを投稿できますが、これは簡単にグーグルで検索できます)を使用して、Windowsサービスが通常LocalServiceまたはNetworkServiceで実行されるのと同じIDを使用できます。

別のIDが必要な場合は、資格情報を使用するかどうかを決定できるapp.configに設定を追加できます。その場合、どのユーザーになりすますか-これらの設定は、アプリとして実行するとアクティブになりますが、Windowsサービスではオフになります(サービスは目的のIDで既に実行されているため)

_  <appSettings>
    <add key="useCredentials" value="false"/>
    <add key="user" value="Foo"/>
    <add key="password" value="Bar"/>
  </appSettings>
_
38
BrokenGlass

通常、手動でブレークポイントを設定し、c#で現在開いているプロジェクトをポイントします。ブレークポイントを設定するコードは次のとおりです。

System.Diagnostics.Debugger.Break();

これで開始できます。コードをステップ実行して、実際に何が起こっているのかを確認できます。

21
Davido

C. Lawrence Wenhamからこれを盗んだので、あまり信用できませんが、次のコードを使用すると、その時点で実行を中断することなく、プログラムでデバッガーをサービスにアタッチできます。

System.Diagnostics.Debugger.Launch();

これをサービスのOnStart()メソッドの最初の行として入力すると、VSのインスタンスを選択してデバッガーをアタッチするように求められます。そこから、システムは設定したブレークポイントで停止し、例外がスローされると停止します。リリースビルドに含まれないように、コードの周りに#if DEBUG句を配置します。または、問題を発見した後にそれを取り除くことができます。

14
KeithS

WinDbg/NTSD(「Windows用デバッグツール」パッケージの別のデバッガー)を使用して、サービスと一緒にデバッガーを開始できます。

これを行うには、「gflags」(上記のパッケージでも利用可能)を開いて「イメージファイル」タブを開き、イメージファイル(サービス)のデバッガー実行可能ファイルへのパスを設定します。

サービスがインタラクティブとしてマークされている場合(SYSTEMアカウントで実行される場合のみ可能)、WinDbgを直接起動できます。デバッガを"PATH_TO_WINDBG\windbg.exe -g -G"( -g/-Gは、デバッガーがアプリケーションの開始時または終了時に実行を中断しないようにするために必要です(デフォルトの動作)。サービスを開始すると、windbgウィンドウがポップアップし、未処理の例外をキャッチします。

サービスが対話型でない場合は、リモートモードでNTSDデバッガー(コマンドラインデバッガー)を起動し、WinDbg(別のPCで実行することもできます)から接続できます。これを行うには、gflagsのデバッガーを"PATH_TO_NTSD\ntsd -remote tcp:port = 6666、server = localhost"のように設定します。次に、"windbg -remote tcp:port = 6666、server = localhost"のようにwindbgを起動してリモートデバッガーに接続すると、他のデバッグセッションを完全に制御できます。

例外のソース自体を見つけることに関しては、windbgチュートリアルがここでのトピックに当てはまりますが、開始として、例外がキャッチされた後に"!analyze -v"コマンドを実行してみてください。必要なすべての情報..

注:多分これはあなたの場合はやり過ぎかもしれませんが、このアプローチではシステムの起動中にサービスをデバッグすることさえできます(サービスのタイミングの問題は、システム)

9
floyd73

私がやることの1つは(ハッキングのようなものかもしれませんが)Thread.Sleep(10000)メソッドの最初にOnStart()を置くことです。これにより、他の処理を行う前にデバッガーをサービスに接続するための10秒間のウィンドウが表示されます。

もちろん、デバッグが終わったらThread.Sleep()ステートメントを削除します。

あなたがするかもしれないもう一つのことは以下です:

_public override void OnStart()
{
    try
    {
        // all your OnStart() logic here
    }
    catch(Exception ex)
    {
        // Log ex.Message
        if (!EventLog.SourceExists("MyApplication"))
            EventLog.CreateEventSource("MyApplication", "Application");

        EventLog.WriteEntry("MyApplication", "Failed to start: " + ex.Message);
        throw;
    }
}
_

_ex.Message_をログに記録すると、より詳細なエラーメッセージが表示される場合があります。さらに、ex.ToString()をログに記録してスタックトレース全体を取得できます。また、.pdbファイルが実行可能ファイルと同じディレクトリにある場合、例外が発生した行も通知されます。

7
Phil

OnStartに多くの詳細なログを追加します。痛くて古い学校ですが、うまくいきます。

6
RQDQ

問題はユーザーコンテキストにあるようです。私の仮定が正しいかどうかを確認させてください。

  1. コードがコンソールアプリケーションから完全に機能すると言うとき、ログインしたのと同じユーザーでコンソールアプリケーションを実行していると思います。

  2. Windowsサービスから呼び出されているときに同じコードがクラッシュすると言うとき、開発マシンの「ローカルシステム」アカウントでサービスが実行されていると思います。

両方の仮定が正しい場合は、次の手順を試してください。

  1. サービスのリストでサービスを右クリックし、プロパティを選択してから「ログオン」タブを選択します。

  2. オプション「このアカウント」を選択し、既存のユーザー名とパスワードを入力します。

  3. 次に、サービスを開始してみてください。これでエラーなしで起動するはずです。

以下がエラーの根本原因である可能性があります

  1. SQL Serverを使用している場合は、SSPI認証を使用していないことを確認してください。

  2. 「ローカルシステム」アカウントを使用しているときに、許可のない共有フォルダー\リソースを読み取ろうとしている場合。

  3. アプリケーションに必要な依存関係のいずれかが、「ローカルシステム」ユーザーがアクセスする権限を持っていない別のフォルダーにある場合。

  4. 「ローカルシステム」アカウントで機能しないVBAオートメーションを使用している場合。

  5. ファイアウォールまたはウイルス対策を無効にしてみてください。

5
AbrahamJP

相互運用呼び出しの周りにログを追加して、どちらが失敗したかを調べることができます。

また、デフォルトではサービスはデスクトップに関連付けられていません。 services.mscコントロールパネルアプレットを開き、サービスのプロパティを取得し、[ログオン]タブに移動すると、[デスクトップとの対話をサービスに許可する]をオンにできます。これにより、場合によっては問題が解決する可能性があります。

4
C.Evenhuis

相互運用性の過剰な使用が原因である可能性があります。したがって、この問題に異なる方法で取り組む必要があります。サービスと同じロジックを使用してWindowsアプリまたはコンソールアプリを作成し、最初に問題なく動作することを確認してから、Winサービスの作成に進むことをお勧めします。

3
Kumar

特に少なくとも私たちにとっては、多くの問題が顕在化するのはスタートアップだと思われるため、サービスのデバッグは苦痛です。

通常は、可能な限り多くのロジックを、開始メソッドと停止メソッドを持つ単一のクラスに抽出します。これらのクラスメソッドは、サービスが直接呼び出すすべてです。次に、2つのボタンを持つWinFormアプリケーションを作成します。1つは開始を呼び出し、もう1つは停止を呼び出します。その後、このWinFormアプリケーションをデバッガから直接実行して、何が起こっているのかを確認できます。

最もエレガントなソリューションではありませんが、それは私たちにとっては有効です。

3
Mike Chess

この質問 をご覧ください。ウィンドウサービスで未処理の例外をキャッチする方法について説明しています。

3
Holstebroe

デバッガをWindowsサービスにアタッチするには、最初に起動する必要があります。サービスの開始に失敗した理由は、Windowsイベントログで確認できます。

その後、デバッガーをアタッチするプロセスは、Visual Studioの[デバッグ]-> [プロセスにアタッチ]から非常に簡単です。

3
TheBoyan

Service OnStartメソッドで次のコードを使用します。

System.Diagnostics.Debugger.Launch();

ポップアップメッセージからVisual Studioオプションを選択する

2
Chirag

私がしたことはOnStart()によって実装され、次のようになります。

_myBusinessObject = new MyBusinessObject();

ビジネスオブジェクトが構築された後、タイマーとIPCハンドラーがすべての実際の(サービス)作業を行います。

このようにすることで、Form_Loadedハンドラーで上記と同じコードを呼び出すForms/WPFアプリケーションを作成できます。このように、Formsアプリケーションのデバッグは、サービスのデバッグとまったく同じです。

唯一の問題は、app.config値を使用している場合、最新の状態に保つ必要がある2番目のapp.configファイルが存在することです。

2
Onion-Knight
1
quimbo