web-dev-qa-db-ja.com

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

Visual StudioでWindowsサービスをデバッグすることはできますか?

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

System.Diagnostics.Debugger.Break();

しかし、それは次のようなコードエラーを与えています:

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

77
PawanS

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

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

enter image description here

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

(多くのグーグルの後、「Visual StudioでWindowsサービスをデバッグする方法」でこれを見つけました。)

59
PawanS

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

System.Diagnostics.Debugger.Launch();

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

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

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

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

サービスプロジェクトは、サービス部分を実装するために必要なシェルだけになります。

Lasse V. Karlsenが提案したとおり、またはデバッガーがアタッチするのを待つループをサービスに設定します。最も簡単なのは

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

... continue with code

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

14
Pauli Østerø

とすれば 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は、デフォルトではフォアグラウンドスレッドであることに注意してください。 faux-serviceスレッドの実行中にreturnからMainingしてもプロセスは終了しません。

6
ta.speot.is

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

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

このコードを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デバッグが完了したら、アプリケーションを再コンパイルして、サービスをインストールします。

Enter image description here

4

コンソールアプリケーションを作成できます。この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サービスのアプリケーションとまったく同じです。

3
kerrubin

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

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

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

2

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

引用します...

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

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

http://windowsservicehelper.codeplex.com/

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

2

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

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

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

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
Sean M

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

System error 1067 has occurred.

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

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

1
Brian

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

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

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

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

Enter image description here

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
Ogglas

Visual Studio独自のビルド後イベントコマンドラインを試してください。

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

@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" > nulなどのメッセージでビルドエラーが発生した場合、 Ctrl + 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 デバッグするには十分なはずです。

1
asakura89

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を作成します。

サービスを開始するには、Visual Studioでデビューするかどうかを確認するメッセージが表示されます。

c:\> sc start text-xyzService

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

c:\> sc stop test-xyzService

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

c:\> sc delete text-xyzService
0
user3942119

Httpを介したWindowsサービスのデバッグ(VS 2015 Update 3および.Net FW 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
mggSoft