Visual StudioでWindowsサービスをデバッグするにはどうすればよいですか?


85

VisualStudioでWindowsサービスをデバッグすることは可能ですか?

私は次のようなコードを使用しました

System.Diagnostics.Debugger.Break();

しかし、次のようなコードエラーが発生しています。

2つのイベントエラーが発生しました。eventID4096VsJITDebuggerと「サービスが開始要求または制御要求にタイムリーに応答しませんでした。」

回答:


124

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

System.Diagnostics.Debugger.Launch();

ポップアップメッセージからVisualStudioオプションを選択します。

注:デバッグモードでのみ#if DEBUG使用するには、次のようにコンパイラ指令を使用できます。これにより、運用サーバーでのリリースモードでの偶発的なデバッグやデバッグを防ぐことができます。

#if DEBUG
    System.Diagnostics.Debugger.Launch();
#endif

9
管理者としてVSを実行することを忘れないでください。その後、リストに表示されます。
マイケル

1
ポップアップメッセージの意味を誰かが明確にできますか?それはいつ/どのように表示されますか?
マイク

@マイク、サービスをインストールして開始すると、表示されます。
Harshit 2015

@Mikeは、インタラクティブな(ログインした)デスクトップにポップアップし、プロセスをデバッグするアプリを選択するかどうかを尋ねるWindowsダイアログボックスです。VSを選択すると、デバッガーが起動してプロセスにアタッチされます
Chris Johnson

63

これを試すこともできます。

  1. Windowsサービスを作成し、インストールして開始します…。つまり、Windowsサービスがシステムで実行されている必要があります。
  2. サービスの実行中に、[デバッグ]メニューに移動し、[プロセスのアタッチ]をクリックします(または古いVisual Studioの)を
  3. 実行中のサービスを見つけて、[すべてのユーザーからのプロセス表示]と[すべてのセッションのプロセスの表示]が選択されていることを確認します。選択されていない場合は選択します。

enter image description here

  1. [添付]ボタンをクリックします
  2. [ OK]をクリックします
  3. [閉じる]をクリックします
  4. ブレークポイントを目的の場所に設定し、実行を待ちます。コードがそのポイントに達すると、自動的にデバッグされます。
  5. ブレークポイントを到達可能な場所に置きonStart()の場合は、サービスを停止して再開することを忘れないでください

(何度もグーグルした後、「VisualStudioでWindowsサービスをデバッグする方法」でこれを見つけました。)


2
VS2013 Update 5ではこのオプションが表示されません。:(
sandeep talabathula 2016年

1
ただし、Vs-2017を管理者として実行する必要があります
chozharajan19年

1
私はこれを試しました。サービスが停止したときにデバッガがアタッチされていない取得しますので、それはONSTARTにonStopでブレークポイントと協力ではなく
KansaiRobot

22

サービスプロジェクトから処理を実行するすべてのコードを別のプロジェクトに分離してから、通常どおり実行およびデバッグできるテストアプリケーションを作成する必要があります。

サービスプロジェクトは、そのサービス部分を実装するために必要なシェルにすぎません。


OOW !! ctrl + C、次にctrl + V、つまり新しいプロジェクトを意味します。やっぱり私だけやってる。個別のプロジェクトではなく、デバッグまたはその他のオプションにプロセスをアタッチすることはできません。
pawanS 2011年

1
もちろん可能ですが、開発中にサービス部分を削除すると、Windowsサービスの開発がはるかに簡単になります。
Lasse V. Karlsen 2011年

うーん...それは良い方法ですが、単に作業が2倍になります。他の方法が存在すると思いました。
pawanS 2011年

9
それがどのように仕事を「倍増」させるのかわかりません。確かに、追加のプロジェクトを作成し、サービス内のコードを3番目のプロジェクトに分離する際に少しオーバーヘッドが追加されますが、それ以外は、コードのコピーを作成せず、移動します。そのプロジェクトを参照します。
Lasse V. Karlsen 2011年

3
^ +1。これにより、サービスの管理作業が2倍になります。これは、開発時間の点ではほとんどゼロであり、1回だけ実行できます。サービスのデバッグは非常に困難です。むしろ、コマンドラインとしてデュアルスタートにします。これを可能にする事前定義されたラッパークラスについてグーグルをチェックしてください(それらはリフレクションを使用してサービスクラスの開始/停止をシミュレートします)。1時間の作業、大量の節約、純損失:マイナス-あなたは時間を稼ぎます。
TomTom 2011年

14

Lasse V. Karlsenによって提案されたとおりにするか、デバッガーが接続するのを待機するループをサービスに設定します。最も単純なのは

while (!Debugger.IsAttached)
{
    Thread.Sleep(1000);
}

... continue with code

このようにして、サービスを開始し、Visual Studio内で[プロセスにアタッチ...]を選択してサービスにアタッチすると、通常の実行が再開されます。


上記のコードをどこに置くべきですか...そしてアタッチプロセスで、disableという名前のサービスを取得しています
PawanS 2011年

3
また、次のようなコードを使用しました if (Environment.UserInteractive) { InteractiveRun(args); } else { Service instance = new Service(); ServiceBase[] servicesToRun = new ServiceBase[] { instance }; ServiceBase.Run(servicesToRun); }
Kirill Kovalenko 2011年

そのコードは、デバッグしたいコードを実行できるようになる前に、できるだけ早くする必要があります。
パウリØsterø

@Pawan:でStart/OnStart()私は推測する
abatishchev

@Kirill:チルダを使用して、コメント内のコードを強調表示します。例foo(bar)
abatishchev 2011年

7

それServiceBase.OnStartprotected可視性を持っているので、私はデバッグを達成するためにリフレクションルートをたどりました。

private static void Main(string[] args)
{
    var serviceBases = new ServiceBase[] {new Service() /* ... */ };

#if DEBUG
    if (Environment.UserInteractive)
    {
        const BindingFlags bindingFlags =
            BindingFlags.Instance | BindingFlags.NonPublic;

        foreach (var serviceBase in serviceBases)
        {
            var serviceType = serviceBase.GetType();
            var methodInfo = serviceType.GetMethod("OnStart", bindingFlags);

            new Thread(service => methodInfo.Invoke(service, new object[] {args})).Start(serviceBase);
        }

        return;
    }
#endif

    ServiceBase.Run(serviceBases);
}

Threadデフォルトでは、フォアグラウンドスレッドであることに注意してください。フェイクサービススレッドの実行中にreturnからMain実行しても、プロセスは終了しません。


OnStartはすぐに戻ることになっているので、別のスレッドでそれを行う必要はありません。ただし、サービスが別のスレッドを開始しない場合、プロセスはすぐに終了します。
マットコノリー

@MattConnolly後者の場合:必要に応じて、上記のコードを変更して、(通常の処理の前に)永久にスリープするフォアグラウンドスレッドを開始します。
ta.speot.is 2013

これは本当の答えになるはずです。美しく動作します!
lentyai

4

Microsoftの記事では、Windowsサービスをデバッグする方法についてここで説明していますでと、プロセスにアタッチしてデバッグした場合に誰もが見逃す可能性のある部分しています。

以下は私の作業コードです。私はマイクロソフトによって提案されたアプローチに従いました。

このコードをに追加しますprogram.cs

static void Main(string[] args)
{
    // 'If' block will execute when launched through Visual Studio
    if (Environment.UserInteractive)
    {
        ServiceMonitor serviceRequest = new ServiceMonitor();
        serviceRequest.TestOnStartAndOnStop(args);
    }
    else // This block will execute when code is compiled as a Windows application
    {
        ServiceBase[] ServicesToRun;
        ServicesToRun = new ServiceBase[]
        {
            new ServiceMonitor()
        };
        ServiceBase.Run(ServicesToRun);
    }
}

このコードをServiceMonitorクラスに追加します。

internal void TestOnStartAndOnStop(string[] args)
{
    this.OnStart(args);
    Console.ReadLine();
    this.OnStop();
}

次に、[プロジェクトのプロパティ]に移動し、[アプリケーション]タブを選択し、デバッグ時に[コンソールアプリケーション]として[出力タイプ]を選択し、デバッグが完了したら[Windowsアプリケーション]を選択して、サービスを再コンパイルしてインストールします。

ここに画像の説明を入力してください


デバッグのコンソールアプリケーションとリリースのウィンドウアプリケーションに出力を設定する方法はありますか?
kofifus

3

コンソールアプリケーションを作成できます。私はこのmain関数を使用します:

    static void Main(string[] args)
    {
        ImportFileService ws = new ImportFileService();
        ws.OnStart(args);
        while (true)
        {
            ConsoleKeyInfo key = System.Console.ReadKey();
            if (key.Key == ConsoleKey.Escape)
                break;
        }
        ws.OnStop();
    }

私のImportFileServiceクラスは、継承(ServiceBase)を除いて、Windowsサービスのアプリケーションとまったく同じです。


同じプロジェクトにあるのか、それともこのコンソールアプリの別のプロジェクトにあるのか
PawanS 2011年

これは、同様のクラスを持つ2つの異なるプロジェクトです。私の場合、これはImportFileServiceクラスのみが重複している単純なサービスです。開発/テストするときは、consoleappを使用してから、コピー/貼り付けします。Lasse V. Karlsenが言ったように、これはデバッグプログラムであり、すべてのロジック(ビジネス)は3番目のプロジェクトにあります。
kerrubin 2011年

OnStartは保護されていませんか?
ジョーフィリップス

はい、そうです。だから「相続人(ServiceBase)を除いて」と言ったのです。コンソールアプリでデバッグする方が簡単だと思いますが、それでもすべての人を納得させることができないかどうかは理解しています。
kerrubin 2012

3

私はServiceProcess.Helpersと呼ばれる素晴らしいNugetパッケージを使用しています。

そして私は引用します...

デバッガーを接続して実行するときに再生/停止/一時停止UIを作成することにより、Windowsサービスのデバッグに役立ちますが、Windowsサーバー環境でサービスをインストールして実行することもできます。

これらすべてを1行のコードで実行できます。

http://windowsservicehelper.codeplex.com/

インストールして配線したら、Windowsサービスプロジェクトをスタートアッププロジェクトとして設定し、デバッガーで[開始]をクリックするだけです。


共有してくれてありがとう!それははるかに簡単な解決策でした!
ウェリントンザ

2

System.Diagnostics.Debugger.Launch()を試すこともできますメソッドをます。デバッガーポインタを指定された場所に移動するのに役立ち、コードをデバッグできます。

この手順の前に、VisualStudioコマンドプロンプトのコマンドラインを使用してservice.exeインストールしてください--installutilprojectservice.exe

次に、[コントロールパネル]-> [管理ツール]-> [コンピューターの管理]-> [サービスとアプリケーション]-> [サービス]-> [サービス名]からサービスを開始します。


2

このコードをサービスクラスに追加したので、OnStopの場合と同様に、間接的にOnStartを呼び出すことができます。

    public void MyOnStart(string[] args)
    {
        OnStart(args);
    }

2

私が使用している/ConsoleVisual Studioのプロジェクトでパラメータをデバッグ開始オプションコマンドライン引数

public static class Program
{
    [STAThread]
    public static void Main(string[] args)
    {
         var runMode = args.Contains(@"/Console")
             ? WindowsService.RunMode.Console
             : WindowsService.RunMode.WindowsService;
         new WinodwsService().Run(runMode);
    }
}


public class WindowsService : ServiceBase
{
    public enum RunMode
    {
        Console,
        WindowsService
    }

    public void Run(RunMode runMode)
    {
        if (runMode.Equals(RunMode.Console))
        {
            this.StartService();
            Console.WriteLine("Press <ENTER> to stop service...");
            Console.ReadLine();

            this.StopService();
            Console.WriteLine("Press <ENTER> to exit.");
            Console.ReadLine();
        }
        else if (runMode.Equals(RunMode.WindowsService))
        {
            ServiceBase.Run(new[] { this });
        }
    }

    protected override void OnStart(string[] args)
    {
        StartService(args);
    }

    protected override void OnStop()
    {
        StopService();
    }

    /// <summary>
    /// Logic to Start Service
    /// Public accessibility for running as a console application in Visual Studio debugging experience
    /// </summary>
    public virtual void StartService(params string[] args){ ... }

    /// <summary>
    /// Logic to Stop Service
    /// Public accessibility for running as a console application in Visual Studio debugging experience
    /// </summary>
    public virtual void StopService() {....}
}

2

この質問を見つけましたが、明確で単純な答えが欠けていると思います。

デバッガーをプロセスにアタッチしたくありませんが、サービスOnStartOnStopメソッドを呼び出せるようにしたいのです。また、NLogから情報をログに記録できるように、コンソールアプリケーションとして実行したいからコンソールに。

私はこれを行うこれらの素晴らしいガイドを見つけました:

プロジェクトOutput typeをに変更することから始めConsole Applicationます。

ここに画像の説明を入力してください

次のように変更しますProgram.cs

static class Program
{
    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    static void Main()
    {
        // Startup as service.
        ServiceBase[] ServicesToRun;
        ServicesToRun = new ServiceBase[]
        {
            new Service1()
        };

        if (Environment.UserInteractive)
        {
            RunInteractive(ServicesToRun);
        }
        else
        {
            ServiceBase.Run(ServicesToRun);
        }
    }
}

次に、次のメソッドを追加して、サービスをインタラクティブモードで実行できるようにします。

static void RunInteractive(ServiceBase[] servicesToRun)
{
    Console.WriteLine("Services running in interactive mode.");
    Console.WriteLine();

    MethodInfo onStartMethod = typeof(ServiceBase).GetMethod("OnStart",
        BindingFlags.Instance | BindingFlags.NonPublic);
    foreach (ServiceBase service in servicesToRun)
    {
        Console.Write("Starting {0}...", service.ServiceName);
        onStartMethod.Invoke(service, new object[] { new string[] { } });
        Console.Write("Started");
    }

    Console.WriteLine();
    Console.WriteLine();
    Console.WriteLine(
        "Press any key to stop the services and end the process...");
    Console.ReadKey();
    Console.WriteLine();

    MethodInfo onStopMethod = typeof(ServiceBase).GetMethod("OnStop",
        BindingFlags.Instance | BindingFlags.NonPublic);
    foreach (ServiceBase service in servicesToRun)
    {
        Console.Write("Stopping {0}...", service.ServiceName);
        onStopMethod.Invoke(service, null);
        Console.WriteLine("Stopped");
    }

    Console.WriteLine("All services stopped.");
    // Keep the console alive for a second to allow the user to see the message.
    Thread.Sleep(1000);
}

素晴らしいコード!シンプルで効果的。+1。しかし、同じように簡単にこれをフォームアプリにしました。私はコンソールアプリが本当に嫌いです。また、サービスイベントごとにフォームボタンを簡単に実装できます。
ローランド

1

残念ながら、Windowsサービス操作の最初に何かをデバッグしようとすると、実行中のプロセスへの「アタッチ」は機能しません。OnStartプロシージャ内でDebugger.Break()を使用しようとしましたが、64ビットのVisual Studio 2010コンパイル済みアプリケーションでは、breakコマンドは次のようなエラーをスローします。

System error 1067 has occurred.

その時点で、実行可能ファイルのレジストリに「イメージファイルの実行」オプションを設定する必要があります。セットアップには5分かかり、非常にうまく機能します。詳細は次のMicrosoftの記事です。

方法:デバッガーを自動的に起動する


1

VisualStudio独自のビルド後のイベントコマンドラインをお試しください

ビルド後にこれを追加してみてください:

@echo off
sc query "ServiceName" > nul
if errorlevel 1060 goto install
goto stop

:delete
echo delete
sc delete "ServiceName" > nul
echo %errorlevel%
goto install

:install
echo install
sc create "ServiceName" displayname= "Service Display Name" binpath= "$(TargetPath)" start= auto > nul
echo %errorlevel%
goto start

:start
echo start
sc start "ServiceName" > nul
echo %errorlevel%
goto end

:stop
echo stop
sc stop "ServiceName" > nul
echo %errorlevel%
goto delete

:end

このようなメッセージでビルドエラーが発生した場合はError 1 The command "@echo off sc query "ServiceName" > nulCtrl+C次にCtrl+Vエラーメッセージをメモ帳に入力して、メッセージの最後の文を確認します。

それは言っている可能性がありますexited with code x。ここでいくつかの一般的なエラーのコードを探し、それを解決する方法を確認してください。

1072 -- Marked for deletion → Close all applications that maybe using the service including services.msc and Windows event log.
1058 -- Can't be started because disabled or has no enabled associated devices → just delete it.
1060 -- Doesn't exist → just delete it.
1062 -- Has not been started → just delete it.
1053 -- Didn't respond to start or control → see event log (if logged to event log). It may be the service itself throwing an exception.
1056 -- Service is already running → stop the service, and then delete.

エラーコードの詳細については、こちらをご覧ください

そして、このようなメッセージでビルドエラーが発生した場合、

Error    11    Could not copy "obj\x86\Debug\ServiceName.exe" to "bin\Debug\ServiceName.exe". Exceeded retry count of 10. Failed.    ServiceName
Error    12    Unable to copy file "obj\x86\Debug\ServiceName.exe" to "bin\Debug\ServiceName.exe". The process cannot access the file 'bin\Debug\ServiceName.exe' because it is being used by another process.    ServiceName

cmdを開き、最初にそれを殺そうとします taskkill /fi "services eq ServiceName" /f

すべてが順調でF5あれば、デバッグするのに十分なはずです。


0

このOnStart方法では、次のようにします。

protected override void OnStart(string[] args)
{
    try
    {
        RequestAdditionalTime(600000);
        System.Diagnostics.Debugger.Launch(); // Put breakpoint here.

        .... Your code
    }
    catch (Exception ex)
    {
        .... Your exception code
    }
}

次に、管理者としてコマンドプロンプトを実行し、次のように入力します。

c:\> sc create test-xyzService binPath= <ProjectPath>\bin\debug\service.exe type= own start= demand

上記の行は、サービスリストにtest-xyzServiceを作成します。

サービスを開始するには、VisualStudioでデビューするかどうかを確認するように求められます。

c:\> sc start text-xyzService

サービスを停止するには:

c:\> sc stop test-xyzService

削除またはアンインストールするには:

c:\> sc delete text-xyzService

0

httpを介してWindowsサービスをデバッグします(VS 2015 Update3および.NetFW 4.6でテスト済み)

まず、VSソリューション内にコンソールプロジェクトを作成する必要があります([追加]-> [新しいプロジェクト]-> [コンソールアプリケーション])。

新しいプロジェクト内で、次のコードを使用してクラス「ConsoleHost」を作成します。

class ConsoleHost : IDisposable
{
    public static Uri BaseAddress = new Uri(http://localhost:8161/MyService/mex);
    private ServiceHost host;

    public void Start(Uri baseAddress)
    {
        if (host != null) return;

        host = new ServiceHost(typeof(MyService), baseAddress ?? BaseAddress);

        //binding
        var binding = new BasicHttpBinding()
        {
            Name = "MyService",
            MessageEncoding = WSMessageEncoding.Text,
            TextEncoding = Encoding.UTF8,
            MaxBufferPoolSize = 2147483647,
            MaxBufferSize = 2147483647,
            MaxReceivedMessageSize = 2147483647
        };

        host.Description.Endpoints.Clear();
        host.AddServiceEndpoint(typeof(IMyService), binding, baseAddress ?? BaseAddress);

        // Enable metadata publishing.
        var smb = new ServiceMetadataBehavior
        {
            HttpGetEnabled = true,
            MetadataExporter = { PolicyVersion = PolicyVersion.Policy15 },
        };

        host.Description.Behaviors.Add(smb);

        var defaultBehaviour = host.Description.Behaviors.OfType<ServiceDebugBehavior>().FirstOrDefault();
        if (defaultBehaviour != null)
        {
            defaultBehaviour.IncludeExceptionDetailInFaults = true;
        }

        host.Open();
    }

    public void Stop()
    {
        if (host == null)
            return;

        host.Close();
        host = null;
    }

    public void Dispose()
    {
        this.Stop();
    }
}

そして、これはProgram.csクラスのコードです。

public static class Program
{
    [STAThread]
    public static void Main(string[] args)
    {
        var baseAddress = new Uri(http://localhost:8161/MyService);
        var host = new ConsoleHost();
        host.Start(null);
        Console.WriteLine("The service is ready at {0}", baseAddress);
        Console.WriteLine("Press <Enter> to stop the service.");
        Console.ReadLine();
        host.Stop();
    }
}

接続文字列などの構成は、コンソールプロジェクトのApp.configファイルにコピーする必要があります。

コンソールを起動するには、コンソールプロジェクトを右クリックし、[デバッグ]-> [新しいインスタンスの開始]をクリックします。


0

サービスクラスにコンストラクターを追加するだけです(まだ持っていない場合)。以下では、Visual Basic.netの確認と例を示します。

Public Sub New()
   OnStart(Nothing) 
End Sub

その後、プロジェクトを右クリックし、「デバッグ->新しいインスタンスの開始」を選択します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.