.NET Coreで作成した Web APIアプリを Windows サービスで動かす

基本は↓に書いてあるのだけど、所々間違っている?というか、バージョンアップあたりで動かなくなっているので、ポイントだけメモ書き。

Windows サービスで ASP.NET Core をホストします。
https://docs.microsoft.com/ja-jp/aspnet/core/host-and-deploy/windows-service?view=aspnetcore-2.0&tabs=aspnetcore2x

https://github.com/aspnet/Docs/tree/master/aspnetcore/host-and-deploy/windows-service/sample

*.csprojでターゲットを.NET Frameworkにする

ASP.NET Core + .NET Core で作成したプロジェクト(*.csproj)を開いて、TargetFramework を「netcoreapp2.0」から「net461」に変える。

  <PropertyGroup>
    <TargetFramework>netcoreapp2.0</TargetFramework>
  </PropertyGroup>

から

  <PropertyGroup>
    <TargetFramework>net461</TargetFramework>
    <RuntimeIdentifier>win7-x64</RuntimeIdentifier>
  </PropertyGroup>

に変更する。

これは Windows サービスを使うために .NET Framework に切り替えているので、Linux上で動かす場合は、netcoreapp2.0 で使うことになる。

NuGetパッケージを変更する

ASP.NET Core を使っているところを、.NET Core から .NET Framework のものに切り替える。あと「Microsoft.AspNetCore.Hosting.WindowsServices」を追加して、Windows サービスで起動するための RunAsService() を使えるようにしておく。

  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.8" />
  </ItemGroup>

から

  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore" Version="2.0.3" />
    <PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.0.4" />
    <PackageReference Include="Microsoft.AspNetCore.Hosting.WindowsServices" Version="2.0.3" />
  </ItemGroup>

Program.csを書き替える

ASP.NET Core + .NET Core の場合には、IWebHost インターフェースを使っているのだが、面倒なので、Main に書き替えてしまう。

public class Program
{
    public static void Main(string[] args)
    {
        BuildWebHost(args).Run();
    }

    public static IWebHost BuildWebHost(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .UseStartup<Startup>()
            .Build();
}

から

using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Hosting.WindowsServices;

public class Program
{
    public static void Main(string[] args)
    {
        bool isService = false;
        if (Debugger.IsAttached || args.Contains("--console"))
        {
            isService = false;
        }
        if ( args.Contains("--service"))
        {
            isService = true;
        }
        // パラメータを消しておく
        args = new string[] { };

        if (isService)
        {
            // サービスで動作させる
            var pathToExe = Process.GetCurrentProcess().MainModule.FileName;
            var pathToContentRoot = Path.GetDirectoryName(pathToExe);
            var host =
                WebHost.CreateDefaultBuilder(args)
                .UseContentRoot(pathToContentRoot)
                .UseStartup<Startup>()
                .Build();
            host.RunAsService();
        }
        else
        {
            // コンソールアプリで起動する
            var host = 
                WebHost.CreateDefaultBuilder(args)
                .UseStartup<Startup>()
                .UseUrls($"http://*:{port}")
                .Build();
            host.Run();
        }
    }
}

起動スイッチを付けて通常起動とサービスの起動に切り替えている。MSのサンプルでは、デフォルトでサービス起動になっているのだが、こちらは「–service」を付けたときだけ、Windows サービスで起動するようにしている。

WebHost.CreateDefaultBuilder に不要なパラメータを渡すと落ちるので、args の中身を消しておく(なんとなくバグ臭いのだが)。

サービスで起動する

サービスを登録するために sc コマンドを管理者権限のコマンドプロンプトで実行する。

sc create UsbService binpath="D:\work\SG\git\usbblocker\UsbBlocker.Web\bin\Debug\net461\win7-x64\UsbBlocker.Web.exe --service"

binpath には、フルパスを指定する。スイッチを付けるためにダブルクォートで囲ってある。サービス名は UsbService としているが、ダブらないように自前で名前をつける。

サービスの起動は sc start でできる。

sb start UsbBlockerService

サービスを削除するときは sc delete する。

sb delete UsbBlockerService
カテゴリー: 開発, C# パーマリンク