Windowsサービスとしての.NETコンソールアプリケーション


145

コンソールアプリケーションがあり、Windowsサービスとして実行したい。VS2010には、コンソールプロジェクトをアタッチしてWindowsサービスを構築できるプロジェクトテンプレートがあります。個別のサービスプロジェクトを追加せずに、可能であればサービスコードをコンソールアプリケーションに統合して、コンソールアプリケーションを、コンソールアプリケーションとして、またはスイッチを使用してコマンドラインから実行する場合はWindowsサービスとして実行できる1つのプロジェクトとして保持します。

たぶん、誰かがクラスライブラリまたはコードスニペットを提案して、c#コンソールアプリケーションをすばやく簡単にサービスに変換できるでしょうか?


一時的なサービスプロジェクトを作成して、それをサービスにするビットをコピーしてみませんか?
Gabe


:あなたはここに記載された技術を試すことができeinaregilsson.com/2007/08/15/...
ジョー・

え?よく分かりません。これについて。

2
非常にシンプルなトップシェルフの代替品:runasservice.com
Luis Perez

回答:


185

私は通常、次のテクニックを使用して、コンソールアプリケーションまたはサービスと同じアプリを実行します。

public static class Program
{
    #region Nested classes to support running as service
    public const string ServiceName = "MyService";

    public class Service : ServiceBase
    {
        public Service()
        {
            ServiceName = Program.ServiceName;
        }

        protected override void OnStart(string[] args)
        {
            Program.Start(args);
        }

        protected override void OnStop()
        {
            Program.Stop();
        }
    }
    #endregion

    static void Main(string[] args)
    {
        if (!Environment.UserInteractive)
            // running as service
            using (var service = new Service())
                ServiceBase.Run(service);
        else
        {
            // running as console app
            Start(args);

            Console.WriteLine("Press any key to stop...");
            Console.ReadKey(true);

            Stop();
        }
    }

    private static void Start(string[] args)
    {
        // onstart code here
    }

    private static void Stop()
    {
        // onstop code here
    }
}

Environment.UserInteractive通常、コンソールアプリの場合はtrue、サービスの場合はfalseです。技術的には、ユーザーインタラクティブモードでサービスを実行することができるため、代わりにコマンドラインスイッチを確認できます。


3
ServiceInstallerクラスを使用します。msdn.microsoft.com/ en- us / library /…を参照してください
VladV 2014年

2
予想通りです-サービスは別のプロセスとして実行されます(したがって、タスクマネージャーに表示されます)が、このプロセスはシステムによって制御されます(たとえば、サービス設定に従って開始、停止、再起動)。
VladV 2016年

2
コンソールアプリとして実行した場合、サービスは表示されません。このコードの目的は、コンソールアプリとして、またはサービスとして実行できるようにすることです。サービスとして実行するには、まずServiceInstallerクラス(上記のMSDNリンクを参照)またはinstalluitil.exeを使用してインストールし、コントロールパネルからサービスを実行する必要があります。
VladV 2016年

2
ServiceInstallerは、Windowsサービスを処理するためのユーティリティクラスです(installutil.exeまたはsc.exeユーティリティに少し似ています)。これを使用して、サービスとして必要なものをインストールできます。OSは、使用するプロジェクトの種類を考慮しません。
VladV 2016年

5
プロジェクトの参照をSystem.ServiceProcessに追加するだけで、上記のコードを使用できるようになります
ダニエル

59

TopShelfで大成功を収めました。

TopShelfは、コンソールアプリまたはWindowsサービスとして実行できる.NET Windowsアプリを簡単に作成できるように設計されたNugetパッケージです。サービスのStartイベントやStopイベントなどのイベントをすばやく接続し、コードを使用して、実行するアカウントを設定したり、他のサービスへの依存関係を構成したり、エラーからの回復方法を構成したりできます。

パッケージマネージャーコンソール(Nuget)から:

インストールパッケージTopshelf

開始するには、コードサンプルを参照してください。

例:

HostFactory.Run(x =>                                 
{
    x.Service<TownCrier>(s =>                        
    {
       s.ConstructUsing(name=> new TownCrier());     
       s.WhenStarted(tc => tc.Start());              
       s.WhenStopped(tc => tc.Stop());               
    });
    x.RunAsLocalSystem();                            

    x.SetDescription("Sample Topshelf Host");        
    x.SetDisplayName("Stuff");                       
    x.SetServiceName("stuff");                       
}); 

TopShelfは、サービスのインストールも処理します。これにより、多くの時間を節約でき、ソリューションから定型コードを削除できます。.exeをサービスとしてインストールするには、コマンドプロンプトから次のコマンドを実行するだけです。

myservice.exe install -servicename "MyService" -displayname "My Service" -description "This is my service."

ServiceInstallerなどを接続する必要はありません-TopShelfがすべてを行います。


1
こんにちは、私はこれを取得しています:-"パッケージ 'Topshelf 4.0.1'をインストールできませんでした。 '。NETFramework、Version = v4.5'をターゲットとするプロジェクトにこのパッケージをインストールしようとしていますが、パッケージには何も含まれていませんそのフレームワークと互換性のあるアセンブリ参照またはコンテンツファイル。」ここで何が問題になっていますか?

3
クライアントプロファイルではなく、完全な.NET 4.5.2ランタイムをターゲットにしていることを確認してください。
2016

myservice.exeに光を当てて、どのディレクトリからコマンドプロンプトを開くか
Izuagbala

1
@Izuagbala myservice.exeは、作成したコンソールアプリケーションで、コードサンプルに示すように、TopShelfがブートストラップされています。
セール:2018年

myservice.exeをサービスとしてインストールした後、コンソールとして実行できますか?ドキュメントは明らかではない:「コンソールアプリケーションが作成されると、開発者は単一のサービスクラスを作成」 docs.topshelf-project.com/en/latest/overview/...
マイケルFreidgeim

27

だからここに完全なチュートリアルがあります:

  1. 新しいコンソールアプリケーションプロジェクト(MyServiceなど)を作成します。
  2. 2つのライブラリ参照を追加します:System.ServiceProcessおよびSystem.Configuration.Install
  3. 以下に印刷された3つのファイルを追加します
  4. プロジェクトをビルドして、「InstallUtil.exe c:\ path \ to \ MyService.exe」を実行します
  5. これで、サービスリストにMyServiceが表示されます(services.mscを実行します)。

* InstallUtil.exeは通常、ここにあります:C:\ windows \ Microsoft.NET \ Framework \ v4.0.30319 \ InstallUtil.ex‌ e

Program.cs

using System;
using System.IO;
using System.ServiceProcess;

namespace MyService
{
    class Program
    {
        public const string ServiceName = "MyService";

        static void Main(string[] args)
        {
            if (Environment.UserInteractive)
            {
                // running as console app
                Start(args);

                Console.WriteLine("Press any key to stop...");
                Console.ReadKey(true);

                Stop();
            }
            else
            {
                // running as service
                using (var service = new Service())
                {
                    ServiceBase.Run(service);
                }
            }
        }

        public static void Start(string[] args)
        {
            File.AppendAllText(@"c:\temp\MyService.txt", String.Format("{0} started{1}", DateTime.Now, Environment.NewLine));
        }

        public static void Stop()
        {
            File.AppendAllText(@"c:\temp\MyService.txt", String.Format("{0} stopped{1}", DateTime.Now, Environment.NewLine));
        }
    }
}

MyService.cs

using System.ServiceProcess;

namespace MyService
{
    class Service : ServiceBase
    {
        public Service()
        {
            ServiceName = Program.ServiceName;
        }

        protected override void OnStart(string[] args)
        {
            Program.Start(args);
        }

        protected override void OnStop()
        {
            Program.Stop();
        }
    }
}

MyServiceInstaller.cs

using System.ComponentModel;
using System.Configuration.Install;
using System.ServiceProcess;

namespace MyService
{
    [RunInstaller(true)]
    public class MyServiceInstaller : Installer
    {
        public MyServiceInstaller()
        {
            var spi = new ServiceProcessInstaller();
            var si = new ServiceInstaller();

            spi.Account = ServiceAccount.LocalSystem;
            spi.Username = null;
            spi.Password = null;

            si.DisplayName = Program.ServiceName;
            si.ServiceName = Program.ServiceName;
            si.StartType = ServiceStartMode.Automatic;

            Installers.Add(spi);
            Installers.Add(si);
        }
    }
}

1
64ビット用にプロジェクトをコンパイルする場合は、64ビット用のInstallUtil.exeを使用する必要があります。これは、C:\ windows \ Microsoft.NET \ Framework64 \ ... 32ビット用のバージョン(C:\ windows \ Microsoft.NET \ Framework)はBadImageFormatExceptionをスローします...
snytek

これは非常にうまく機能します。@ snytekが言うように、base 64を使用している場合は、正しいディレクトリを使用していることを確認してください。また、私と同じことをしていて、サービスの名前を「MyService」以外に変更し忘れた場合は、コードを変更する前に、サービスをアンインストールしてください。
dmoore1181

3

1つのアセンブリに繰り返しコードを停止させたいというあなたの意見を聞きましたが、これは最も簡単で、コードの繰り返しを減らし、将来他の方法でコードを再利用しやすくなります。

  1. すべての作業を行う1つのライブラリアセンブリ。次に、非常にスリムでシンプルな2つのプロジェクトがあります。
  2. コマンドラインであるもの
  3. 1つはWindowsサービスです。

1
これは私が年のためにそれをやった方法です-サービスはかなり持っているStart()と、Stop()メソッドやコンソールアプリケーションは、ループを持っています。TopShelfのようなフレームワークを使用するのではなく、これが最良のオプションです
基本

その答えに最も同意します。シンプルなソリューションにサードパーティツールを使用すると、将来のメンテナンスが不要になります
tatigo

3

最新の.Net Core 3.1に基づいて、コンソールアプリケーションをワーカーサービスとしてWindowsサービスに変換する新しい方法を次に示します。ます。

Visual Studio 2019からワーカーサービスを作成すると、Windowsサービスを作成するために必要なほぼすべてのものが提供されます。これは、コンソールサービスをWindowsサービスに変換するために変更する必要があるものでもあります。

以下に、必要な変更を示します。

次のNuGetパッケージをインストールする

Install-Package Microsoft.Extensions.Hosting.WindowsServices -Version 3.1.0
Install-Package Microsoft.Extensions.Configuration.Abstractions -Version 3.1.0

Program.csを以下のような実装に変更します。

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

namespace ConsoleApp
{
    class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).UseWindowsService().Build().Run();
        }

        private static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureServices((hostContext, services) =>
                {
                    services.AddHostedService<Worker>();
                });
    }
}

サービスオペレーションによって実行されるコードを配置するWorker.csを追加します。

using Microsoft.Extensions.Hosting;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp
{
    public class Worker : BackgroundService
    {
        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            //do some operation
        }

        public override Task StartAsync(CancellationToken cancellationToken)
        {
            return base.StartAsync(cancellationToken);
        }

        public override Task StopAsync(CancellationToken cancellationToken)
        {
            return base.StopAsync(cancellationToken);
        }
    }
}

すべての準備が整い、アプリケーションが正常にビルドされたら、sc.exe使用して、次のコマンドでコンソールアプリケーションのexeをWindowsサービスとしてインストールできます

sc.exe create DemoService binpath= "path/to/your/file.exe"

2

使用できます

reg add HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run /v ServiceName /d "c:\path\to\service\file\exe"

そして、それはサービスリストに表示されます。それが正しく機能するかどうかはわかりません。サービスは通常、いくつかのイベントをリッスンする必要があります。

ただし、いくつかのサービスラッパーがあり、任意のアプリケーションを実際のサービスとして実行できます。たとえば、Win2003リソースキットの Microsofts SrvAny


あなたが言うように、service exeはWindowsと通信する必要があります。+1(SrvAnyへのリンク)
Jodrell

5
このアプローチは安全ではないと思います。Windowsには、サービスを管理するための特別なライブラリとユーティリティがあり、異なるOSバージョンや環境で一貫して機能する可能性が高くなります。.NETアプリの場合、VSでMSIインストーラーを作成するのは非常に簡単です。ManagedInstallerClass.InstallHelperメソッドを使用してプログラムでインストールを実行することもできます。
VladV、2011年

1
インストーラーなどは必要ありません。次のコマンドラインを使用してください:sc create MyServiceName binPath = "c:\ path \ to \ service \ file \ exe"
JDC

2

まず、コンソールアプリケーションソリューションをWindowsサービスソリューションに埋め込み、参照します。

次に、コンソールアプリケーションのProgramクラスを公開します。

/// <summary>
/// Hybrid service/console application
/// </summary>
public class Program
{
}

次に、コンソールアプリケーション内に2つの関数を作成します

    /// <summary>
    /// Used to start as a service
    /// </summary>
    public void Start()
    {
        Main();
    }

    /// <summary>
    /// Used to stop the service
    /// </summary>
    public void Stop()
    {
       if (Application.MessageLoop)
            Application.Exit();   //windows app
        else
            Environment.Exit(1);  //console app
    }

次に、Windowsサービス自体の中でプログラムをインスタンス化し、OnStartおよびOnStop内に追加されたStartおよびStop関数を呼び出します。下記参照

class WinService : ServiceBase
{
    readonly Program _application = new Program();

    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    static void Main()
    {
        ServiceBase[] servicesToRun = { new WinService() };
        Run(servicesToRun);
    }

    /// <summary>
    /// Set things in motion so your service can do its work.
    /// </summary>
    protected override void OnStart(string[] args)
    {
        Thread thread = new Thread(() => _application.Start());
        thread.Start();
    }

    /// <summary>
    /// Stop this service.
    /// </summary>
    protected override void OnStop()
    {
        Thread thread = new Thread(() => _application.Stop());
        thread.Start();
    }
}

このアプローチは、WindowsアプリケーションとWindowsサービスのハイブリッドにも使用できます。


これは基本的にJonAlbが前の回答で言ったことですが、コード例に感謝します
tatigo

0

おそらく、私が知る限り、必要なものを定義する必要があります。アプリをコマンドラインでコンソールまたはサービスとして同時に実行することはできません。サービスがインストールされ、サービスマネージャーで開始する必要があることに注意してください。サービスを開始するか、コンソールアプリを実行する新しいプロセスを開始する新しいアプリケーションを作成できます。しかし、あなたが書いたように

「コンソールアプリケーションを1つのプロジェクトとして保持する」

かつて、私はあなたの立場にいて、コンソールアプリケーションをサービスに変えました。VS Express Editionを使用している場合は、最初にテンプレートが必要です。最初のステップを実行できるリンクは次のとおりです。C#Windowsサービス。これは私にとって非常に役に立ちました。次に、そのテンプレートを使用して、サービスの目的のイベントにコードを追加します。

サービスを改善するためにできることは他にもありますが、これは迅速かつ/または簡単ではなく、appdomainsを使用し、ロード/アンロードするDLLを作成します。1つはコンソールアプリで新しいプロセスを開始する方法で、もう1つはサービスで実行する必要のある機能をDLLに追加する方法です。

幸運を。


0

機能を1つまたは複数のクラスに分離し、2つのスタブのいずれかを介してそれを起動する必要があります。コンソールスタブまたはサービススタブ。

わかりやすいように、ウィンドウを実行しているとき、インフラストラクチャを構成する無数のサービスは、ユーザーにコンソールウィンドウを表示しません(直接表示することもできません)。サービスは、非グラフィカルな方法でユーザーと通信する必要があります。SCMを介して。イベントログ、ログファイルなどに記録されます。サービスはSCMを介してWindowsと通信する必要もあり、そうでない場合はシャットダウンされます。

サービスと通信できるコンソールアプリがあれば十分ですが、サービスはGUIの対話を必要とせずに独立して実行する必要があります。

コンソールスタブは、サービスの動作のデバッグに非常に役立ちますが、結局のところ、サービスを作成する目的である「本稼働」環境では使用しないでください。

私はそれを完全には読んでいませんが、この記事は正しい方向に向かっているようです。


0

私は、で規定された標準パターンに従うサービスクラスを使用し、ServiceBaseF5デバッグを容易にするヘルパーを追加しています。これにより、サービス内で定義されたサービスデータが保持されるため、データを見つけやすくなり、ライフタイムを簡単に管理できます。

私は通常、以下の構造を持つWindowsアプリケーションを作成します。コンソールアプリケーションは作成しません。そうすれば、アプリを実行するたびに大きなブラックボックスが顔に飛び出さなくなります。私はすべてのアクションがあるデバッガーにとどまります。私が使うDebug.WriteLineメッセージを出力ウィンドウに送るためします。出力ウィンドウはうまくドッキングし、アプリが終了しても表示されたままになります。

私は通常、わざわざ停止するためのデバッグコードを追加しません。代わりにデバッガを使用します。停止をデバッグする必要がある場合は、プロジェクトをコンソールアプリにして、Stopフォワーダーメソッドを追加し、への呼び出し後に呼び出しますConsole.ReadKey

public class Service : ServiceBase
{
    protected override void OnStart(string[] args)
    {
        // Start logic here.
    }

    protected override void OnStop()
    {
        // Stop logic here.
    }

    static void Main(string[] args)
    {
        using (var service = new Service()) {
            if (Environment.UserInteractive) {
                service.Start();
                Thread.Sleep(Timeout.Infinite);
            } else
                Run(service);
        }
    }
    public void Start() => OnStart(null);
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.