LoginSignup
17
21

More than 3 years have passed since last update.

.NET5でWindowsServiceを作成する

Last updated at Posted at 2021-03-28

はじめに

.NET5が登場してからこの記事の執筆時点でもうすぐ半年が過ぎようとしています。
しかしながら、日本語での.NET5の記事があまりありませんでしたので、せっかくなので作成しようと思いました。
よろしければご参考程度にご確認ください。
また、この記事で紹介しているコードは以下のリポジトリに配置しております。

実行環境

  • VisualStudio2019
  • Windows10Pro 20H2 (Build: 19042.867)
  • .NET5 SDK 5.0.1

参考

実装

プロジェクトの作成

  1. まず、VisualStudioで新しいプロジェクトを作成します。
  2. 数多く作成できるプロジェクトはありますが、その中から WorkerService を選択します。 Microsoft Visual Studio 2021_03_28 12_57_40.png
  3. いつも通り、プロジェクト名と作成先の場所を指定します Microsoft Visual Studio 2021_03_28 12_58_11.png
  4. WorkerService の作成の画面が出てきます。作成しましょう。
    1. ここでは私は.NET5を左上で選択しておきます。
    2. Dockerサポートは使用しない為、チェックがされている場合はチェックを外しておきます。 Microsoft Visual Studio 2021_03_28 12_58_23.png
  5. 次のようにいつものソリューションエクスプローラーが表示されたなら、プロジェクトの作成に成功です。 WindowsServiceTest - Microsoft Visual Studio 2021_03_28 12_58_51.png

実際のコードの実装

事前準備

コードの実装をいきなり行いたいのはやまやまですが、このままでは.NET5でのWindowsServiceは行えません。
ので、事前準備を実施します。


ソリューションエクスプローラーからプロジェクトを右クリックし、「NuGetパッケージの管理」を選択します。
開かれたNuGetの管理画面から「参照」タブを選択し、 Microsoft.Extensions.Hosting.WindowsService で検索します。
一番上にMicrosoft公式のパッケージが出てくるかと思います。そちらをインストールしてください。
WindowsServiceTest - Microsoft Visual Studio 2021_03_28 13_03_26.png

次に、ソリューションエクスプローラーから Program.cs を開き、次のように、最後に .UseWindowsService() を追加してあげてください。


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();
}

これで、WindowsServiceの一番ミニマムな実装は完了です。

せっかくなので気象庁のAPIもどきを叩いてお天気を60分に1回取ってきてみてもいいよね

この記事を書く少し前の時期に「気象庁のサイトにAPIが生えている」という話題が上がりました。
何もしないWindowsServiceも味気ないので、せっかくなのでこのAPIにアクセスしてみようと思います。
ちなみに、ここまでのミニマムな実装のままだと、WindowsServiceは1秒に1回実行する待機処理(ポーリング)をしており、
そのポーリング処理にAPIアクセスをまともに乗せると後でめちゃくちゃ怒られそうなので、1時間に1回にしようと考えます。

まずは1時間に1回の実行に変更

ポーリング処理とは言いましたが、その実態は ExecuteAsync() 内で while() があり、その中で Task.Delay() して実行間隔を制御しているにすぎません。
ですので、その Task.Delay() の間隔を変更してやればよいです。

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

気象庁APIにアクセスする

C#だと、HttpClientクラスがありますので、そちらを使用します

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            while (!stoppingToken.IsCancellationRequested)
            {
+               var client = new HttpClient();
+               var response = await client.SendAsync(new(HttpMethod.Get, @"https://www.jma.go.jp/bosai/forecast/data/forecast/130000.json"));
+               var body = await response?.Content.ReadAsStringAsync() ?? "";
+               _logger.LogInformation("response content: " + body);
                _logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
                await Task.Delay(360000, stoppingToken);
            }
        }

このように取ってきたデータが表示されていればOKです。
なお、WindowsServiceと仰々しい名前がついていますが、VisualStudioで起動したり、exeを単体実行する分には ただのコンソールアプリケーションとして扱え ますので、普通にデバッグ実行してあげるとこのようにデバッグコンソールから確認することができます。

Microsoft Visual Studio デバッグ コンソール 2021_03_28 13_58_03.png

せっかくなので、WindowsServiceへのサービス起動時処理、サービス終了時処理の生やし方も

このように生やせます。 (VisualStudioを使っているなら、 override キーワードを挿入すると勝手にサジェストされるので、そちらを確認したほうが良いかもしれませんね。)

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

        public Worker(ILogger<Worker> logger)
        {
            _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);
            }
        }
    }

備考

サービスの登録の方法について

アプリを配布する際にサービスへの登録が必要かと思いますが、普通、サービスの登録はユーザには操作させることはできないでしょう。 (一般ユーザーにとって、それは難易度が非常に高いものです。)
ですので、次の記事でWindowsServiceをインストール時に登録ができるインストーラーと、その使用方法を紹介したいと考えます。

おわりに

このような形で、.NET5でWindowsServiceは作成することができます。
同じ開発者の助けになる記事になることを望みます。

また、何か誤っている個所がありましたらご指摘ください。
ここまで読んでくださり、ありがとうございました。

次回

17
21
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
17
21