はじめに
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サービスで実行できるようになります。
- NuGetで
Microsoft.Extensions.Hosting.WindowsServiceをインストールする Program.csでUseWindowsService()拡張メソッドの呼び出しを追加する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.csのExecuteAsyncメソッドに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が作成されます。


serviceProcessInstaller1とserviceInstaller1のプロパティで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("システムシャットダウン");
}
}
}
アプリ作成
リリースビルド(もしくはデバッグビルド)する。

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

さいごに
「.NET 7.0」と「.NET Framework 4.8」でWindowsサービスの開発方法をまとめした。
「.NET 7.0」のほうが、デバッグが容易で開発しやすいように思いました。
| フレームワーク | .NET 7.0 | .NET Framework 4.8 |
|---|---|---|
| プロジェクトテンプレート | ワーカーサービス | Windowsサービス |
| デバッグ | 容易(F5でできる) | 面倒(サービス起動&アタッチ) |
| サービスの管理 | scコマンド | installutilコマンド |
参考サイト
- ワーカーサービス(.NET 7.0)
- Windowsサービス(.NET Framework 4.8)