Windowsサービス関連記事
やりたいこと
以前、C++やC#(.NET Framework)でサービスを作ったが、C#(.NET5)だとまた違う作り方があるらしい。
それをやってみる。
やり方
.NET5の「ワーカー サービス」のテンプレートを使用する。
前提
VisualStudio2019 / .NET5.0
手順
■プロジェクト作成
新しいプロジェクトの作成で「ワーカー サービス」を選択しプロジェクトを作成する。
プロジェクトを作成したら、こういう構成になっている。
■Microsoft.Extensions.Hosting.WindowsServices をインストール
作成したプロジェクト(ここでは**「MyService」**)の「Nugetの管理」を開き、「Microsoft.Extensions.Hosting.WindowsServices」のパッケージを検索、インストールする。1
※「Microsoft.Extensions.Hosting」のほうは、プロジェクトのテンプレートに元からインストールされているもの。
■IHostBuilder CreateHostBuilder(string[] args)を修正
Host.CreateDefaultBuilder(args)・・・
している部分の一番後ろに、
.UseWindowsService();
を付ける。
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。何度も同じコマンド打つのが面倒なので今回はバッチをつくった)
@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.cs
のTask ExecuteAsync(CancellationToken stoppingToken)
が、サービスの処理を書くためのメソッド。
ここに、やりたい処理を書く。
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()」をオーバーライドし、そこに処理を書く。
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);
}
}
}
}
■サービスの「スタートアップの種類」や「説明」を変えたいとき
サービスをインストールするときのscコマンドで変更する。
例えばこうすると
rem サービスインストール
sc create %SERVICENAME% binPath= %EXEPATH% start= auto
sc description %SERVICENAME% setumeibun
WorkerServiceでの、サービスの「一時停止」「再開」はどうやる?
「一時停止」「再開」は、WOrkerServiceを使ったWindowsサービスでは存在しないっぽい。→つまり、できない。
下記記事では、昔のwindowsサービスから今のWorkerServiceに乗り換える場合は、サービスの再設計が必要、とある。
参考
Microsoft.Extensions.Hosting.WindowsServices のパッケージのインストールが必要。
また「.UseWindowsService();」の追記が必要。
動画でサービスの作り方を説明(英語・短い)
動画でサービスの作り方を説明(英語・長いけど詳しい)
「WorkerService」を「WindowsService」にする
https://youtu.be/PzrTiz_NRKA?t=1774
MS公式
scコマンド(Create)
scコマンドDescriptionn)
-
今回.NET5で試したので、「ワーカーサービス」のテンプレートに元から入っている6.0.0ではなく5.0.0を使用。
Microsoft.Extensions.Hosting
のバージョンに合わせてMicrosoft.Extensions.Hosting.WindowsServices
のバージョンを選ぶ必要あり。 ↩