はじめに

C#でWindowsサービスを開発する方法をフレームワーク毎にまとめました。
フレームワークによって、Visual Studioのプロジェクトテンプレートが異なります。

  • .NET 7.0であれば、「ワーカーサービス」を選択する
    イメージ
  • .NET Framework 4.8であれば、「Windowsサービス」を選択する
    イメージ

今回使用したサンプルコードはGitHubのリポジトリにあります。

環境

  • Windows 10 64bit
  • Visual Studio Community 2022
  • C#
  • .NET 7.0
  • .NET Framework 4.8

開発手順

ワーカーサービス(.NET 7.0)

プロジェクト作成

Visual StudioでWindowsサービスを開発するためのプロジェクトを作成します。
プロジェクトテンプレートは「ワーカーサービス」を選択して次へ進み、お好みの名前でプロジェクトを作成します。
イメージ
プロジェクトのデフォルトの構成は下記のようになっております。
イメージ

事前準備

プロジェクトテンプレートのデフォルトのままでは、アプリ*.exeをWindowsサービスで実行するとエラーとなります。デスクトップ環境でアプリ*.exeを実行するとエラーになりません。
イメージ

下記の手順で、アプリ*.exeをWindowsサービスで実行できるようになります。

  1. NuGetでMicrosoft.Extensions.Hosting.WindowsServiceをインストールする
  2. Program.csUseWindowsService()拡張メソッドの呼び出しを追加する
    namespace WorkerService
    {
     public class Program
     {
         public static void Main(string[] args)
         {
             IHost host = Host.CreateDefaultBuilder(args)
    +               .UseWindowsService()
                 .ConfigureServices(services =>
                 {
                     services.AddHostedService<Worker>();
                 })
                 .Build();
    
             host.Run();
         }
     }
    }
    

処理を書く

Worker.csExecuteAsyncメソッドにWindowsサービスで行いたい処理を書きます。
ExecuteAsyncはサービス開始時に呼び出され、デフォルトでは周期処理となっております。

namespace WorkerService
{
    public class Worker : BackgroundService
    {
        private readonly ILogger<Worker> _logger;

        public Worker(ILogger<Worker> logger)
        {
            _logger = logger;
        }

        /// <summary>
        /// サービス定周期処理
        /// </summary>
        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            while (!stoppingToken.IsCancellationRequested)
            {
                _logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
                await Task.Delay(1000, stoppingToken);
            }
        }
    }
}

デバッグ

Visual Studioの他のアプリケーション開発と同じようにデバッグ実行(F5実行)できブレークポイントを張ってステップ実行や変数のウォッチができます。
イメージ

アプリ作成

Windowsサービスで実行するアプリ*.exeを作成します。
Visual Studioのソリューションエクスプローラーで当該プロジェクトを右クリックして「発行」を選択する。
イメージ
「フォルダー」を選択して次へ進み、デフォルトのまま完了する。
イメージ
「発行」をクリックしてアプリ*.exeを作成する。
イメージ

Windowsサービス管理

Windowsサービスの作成、削除はscコマンドで行います。
scコマンド管理者権限で実行します。scコマンドの使い方はここを参考にさせて頂きました。

Windowsサービス作成

sc createで、作成したアプリ*.exeをWindowsサービスに登録します。

sc create {サービス名} binPath= {*.exeのパス}
sc description {サービス名} "説明"

管理者権限のコマンドプロンプトで実行すると、Windowsサービスが作成されます。

C:\WINDOWS\system32>sc create WorkerService binPath= "パス\WorkerService.exe"
[SC] CreateService SUCCESS

C:\WINDOWS\system32>sc description WorkerService "ワーカーサービス"
[SC] ChangeServiceConfig2 SUCCESS

イメージ
イメージ

Windowsサービス削除

sc deleteで、Windowsサービスを削除します。

sc delete {サービス名}

管理者権限のコマンドプロンプトで実行すると、Windowsサービスが削除されます。

C:\WINDOWS\system32>sc delete WorkerService
[SC] DeleteService SUCCESS

Windowsサービス(.NET Framework 4.8)

プロジェクト作成

Visual StudioでWindowsサービスを開発するためのプロジェクトを作成します。
プロジェクトテンプレートは「Windowsサービス」を選択して次へ進み、お好みの名前でプロジェクトを作成します。
イメージ
プロジェクトのデフォルトの構成は下記のようになっております。
イメージ

事前知識

.NET Framework 4.8で作成したアプリ*.exeはWindowsサービスでないと実行できません。
デスクトップ環境でアプリ*.exeを実行するとエラーになります。
イメージ
そのため、デバッグはWindowsサービスにアタッチして行うことになります。

事前準備

.NET Framework 4.8では、installutilコマンドで、作成したアプリ*.exeをWindowsサービスに登録したり削除します。
installutilコマンドで登録/削除できるようにVisual Studioでインストーラーを作成します。
Service1.csのデザインを開き、何もないところで右クリックし「インストーラーの追加」を選択します。
イメージ
ProjectInstaller.csが作成されます。
イメージ
イメージ
serviceProcessInstaller1serviceInstaller1のプロパティでWindowsサービスの設定を指定できます。
イメージ
イメージ

Windowsサービス管理

installutilコマンド管理者権限で実行します。

Windowsサービス作成

installutilで、作成したアプリ*.exeをWindowsサービスに登録します。

installutil *.exe

管理者権限のDeveloper Command Prompt for VS 2022で実行すると、Windowsサービスが作成されます。

**********************************************************************
** Visual Studio 2022 Developer Command Prompt v17.4.5
** Copyright (c) 2022 Microsoft Corporation
**********************************************************************

C:\Windows\System32>installutil パス\WindowsService.exe
Microsoft(R) .NET Framework Installation utility Version 4.8.4084.0
Copyright (C) Microsoft Corporation. All rights reserved.


トランザクションのインストールを実行中です。

~~~ 省略 ~~~

コミット段階が正常に終了しました。

トランザクション インストールが完了しました。

イメージ
イメージ

serviceProcessInstaller1のプロパティで、Windowsサービスの実行アカウントを「User」にすると、 イメージ
installutil実行時にユーザーの入力ダイアログが表示されます。
イメージ

Windowsサービス削除

installutil/uオプションで、Windowsサービスを削除します。

installutil /u *.exe

管理者権限のDeveloper Command Prompt for VS 2022で実行すると、Windowsサービスが削除されます。

**********************************************************************
** Visual Studio 2022 Developer Command Prompt v17.4.5
** Copyright (c) 2022 Microsoft Corporation
**********************************************************************

C:\Windows\System32>installutil /u パス\WindowsService.exe
Microsoft(R) .NET Framework Installation utility Version 4.8.4084.0
Copyright (C) Microsoft Corporation. All rights reserved.


アンインストールを開始します。

~~~ 省略 ~~~

アンインストールか完了しました。

イベント設定

イベントは、Service1.cs[デザイン]のプロパティから使用する(True)/ 使用しない(False)を指定します。 イメージ
使用する(True)になっていると、Windowsサービスのプロパティからイベントが選択できるようになります。
イメージ

処理を書く

Service1.csに、イベントに応じたメソッドを用意し、Windowsサービスで行いたい処理を書きます。

メソッド名 イベント デフォルト有無
OnStart サービス開始 デフォルトである
OnStop サービス停止 デフォルトである
OnPause サービス一時停止 デフォルトではない
OnContinue サービス再開 デフォルトではない
OnShutdown シャットダウン デフォルトではない
using NLog;
using System.ServiceProcess;
using System.Timers;

namespace WindowsService
{
    public partial class Service1 : ServiceBase
    {
        private static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger();

        public Service1()
        {
            InitializeComponent();
        }

        /// <summary>
        /// サービス開始処理
        /// </summary>
        protected override void OnStart(string[] args)
        {
            Logger.Info("サービス開始処理");

            // Set up a timer that triggers every minute.
            System.Timers.Timer timer = new System.Timers.Timer();
            timer.Interval = 1000; // 1 seconds
            timer.Elapsed += new ElapsedEventHandler(this.OnTimer);
            timer.Start();
        }

        /// <summary>
        /// 周期処理
        /// </summary>
        private void OnTimer(object sender, ElapsedEventArgs args)
        {
            Logger.Info("周期処理");
        }

        /// <summary>
        /// サービス停止処理
        /// </summary>
        protected override void OnStop()
        {
            Logger.Info("サービス停止処理");
        }
        /// <summary>
        /// サービス一時停止処理
        /// </summary>
        protected override void OnPause()
        {
            Logger.Info("サービス一時停止");
        }

        /// <summary>
        /// サービス再開処理
        /// </summary>
        protected override void OnContinue()
        {
            Logger.Info("サービス再開");
        }

        /// <summary>
        /// システムシャットダウン処理
        /// </summary>
        protected override void OnShutdown()
        {
            Logger.Info("システムシャットダウン");
        }
    }
}

アプリ作成

リリースビルド(もしくはデバッグビルド)する。
イメージ

デバッグ

デバッグまでの流れ

  1. アプリ*.exeをWindowsサービスに登録する
  2. Windowsサービスを開始する
  3. 管理者権限でVisual Studioを実行し、「デバッグ」>「プロセスにアタッチ」を選択する
  4. 当該サービスを選択し、アタッチする(サービスが表示されないときは「すべてのユーザーのプロセスを表示する」にチェックを入れる)
  5. ブレークポイントを張って、ステップ実行や変数をウォッチする
    イメージ

さいごに

「.NET 7.0」と「.NET Framework 4.8」でWindowsサービスの開発方法をまとめした。
「.NET 7.0」のほうが、デバッグが容易で開発しやすいように思いました。

フレームワーク .NET 7.0 .NET Framework 4.8
プロジェクトテンプレート ワーカーサービス Windowsサービス
デバッグ 容易(F5でできる) 面倒(サービス起動&アタッチ)
サービスの管理 scコマンド installutilコマンド

参考サイト