LoginSignup
16
22

More than 1 year has passed since last update.

[C#] C#でサービスを作る(.NET5.0)

Last updated at Posted at 2021-12-27

Windowsサービス関連記事

やりたいこと

以前、C++やC#(.NET Framework)でサービスを作ったが、C#(.NET5)だとまた違う作り方があるらしい。
それをやってみる。

やり方

.NET5の「ワーカー サービス」のテンプレートを使用する。

前提

VisualStudio2019 / .NET5.0

手順

■プロジェクト作成

新しいプロジェクトの作成で「ワーカー サービス」を選択しプロジェクトを作成する。
image.png
プロジェクトを作成したら、こういう構成になっている。
image.png

■Microsoft.Extensions.Hosting.WindowsServices をインストール

作成したプロジェクト(ここでは「MyService」)の「Nugetの管理」を開き、「Microsoft.Extensions.Hosting.WindowsServices」のパッケージを検索、インストールする。1
image.png
※「Microsoft.Extensions.Hosting」のほうは、プロジェクトのテンプレートに元からインストールされているもの。

■IHostBuilder CreateHostBuilder(string[] args)を修正

Host.CreateDefaultBuilder(args)・・・している部分の一番後ろに、
.UseWindowsService();を付ける。

Program.cs
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

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

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureServices((hostContext, services) =>
                {
                    services.AddHostedService<Worker>();
                }).UseWindowsService();// ★★←これを追加
    }
}

「これを追加」の部分以外は、テンプレートで生成されたコードそのまま。

これで、このプロジェクトをビルドしてできる「MyService.exe」を、サービスとして動かす準備はできた。
ビルドすると、標準でMyService\MyService\bin\Debug\net5.0 のようなフォルダにexeができる。

■サービスとしてPCに入れる

下記のバッチファイルを作成し、ビルドしてできたexeと同じフォルダに置き、管理者で実行する。今回は、サービス名=MyServiceとした。
(個別にscコマンドでインストールを行ってもOK。何度も同じコマンド打つのが面倒なので今回はバッチをつくった)

InstallMyService.bat
@echo off
set SERVICENAME="MyService"
set EXEPATH="%~dp0MyService.exe"

rem 2回目以降の実験のために、まずサービスを止めて、古いのを一度消す
net stop %SERVICENAME%
sc delete %SERVICENAME%

rem サービスインストール
sc create %SERVICENAME% binPath= %EXEPATH%

rem サービス開始
net start %SERVICENAME%

これで、テンプレートのまんまの、1秒おきにログを取るだけのサービスが動いた。

■サービスで行いたい処理を実装する

Worker.csTask ExecuteAsync(CancellationToken stoppingToken)が、サービスの処理を書くためのメソッド。
ここに、やりたい処理を書く。

Worker.cs
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

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

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

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            while (!stoppingToken.IsCancellationRequested)
            {
                // ★★ここに、やりたいことを書く★★
                _logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
                await Task.Delay(1000, stoppingToken);
            }
        }
    }
}

コメント以外は、テンプレートで生成されたコードそのまま。
下の「参考」に挙げたようなサイトでは、ここにHTTPサーバーの機能を記述する、などされていた。

■サービスの開始時や終了時になにかしたいとき

BackgroundServiceクラスの「StartAsync()」「StopAsync()」をオーバーライドし、そこに処理を書く。

startとstopを追加したWorker.cs
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

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

        public Worker(ILogger<Worker> logger)
        {
            Thread.Sleep(10000);
            _logger = logger;
        }

        public override Task StartAsync(CancellationToken cancellationToken)
        {
            // ここにサービス開始時の処理を書く
            return base.StartAsync(cancellationToken);
        }

        public override Task StopAsync(CancellationToken cancellationToken)
        {
            // ここにサービス終了時の処理を書く
            return base.StopAsync(cancellationToken);
        }

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            while (!stoppingToken.IsCancellationRequested)
            {
                _logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
                await Task.Delay(1000, stoppingToken);
            }
        }
    }
}

■サービスの「スタートアップの種類」や「説明」を変えたいとき

この辺を変えたいとき。
image.png

サービスをインストールするときのscコマンドで変更する。

例えばこうすると

rem サービスインストール
sc create %SERVICENAME% binPath= %EXEPATH% start= auto
sc description %SERVICENAME% setumeibun

こうなる。
image.png

WorkerServiceでの、サービスの「一時停止」「再開」はどうやる?

「一時停止」「再開」は、WOrkerServiceを使ったWindowsサービスでは存在しないっぽい。→つまり、できない。
下記記事では、昔のwindowsサービスから今のWorkerServiceに乗り換える場合は、サービスの再設計が必要、とある。

参考

Microsoft.Extensions.Hosting.WindowsServices のパッケージのインストールが必要。
また「.UseWindowsService();」の追記が必要。

動画でサービスの作り方を説明(英語・短い)

動画でサービスの作り方を説明(英語・長いけど詳しい)

「WorkerService」を「WindowsService」にする
https://youtu.be/PzrTiz_NRKA?t=1774

MS公式

scコマンド(Create)

scコマンドDescriptionn)


  1. 今回.NET5で試したので、「ワーカーサービス」のテンプレートに元から入っている6.0.0ではなく5.0.0を使用。Microsoft.Extensions.Hostingのバージョンに合わせてMicrosoft.Extensions.Hosting.WindowsServicesのバージョンを選ぶ必要あり。 

16
22
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
16
22