web-dev-qa-db-ja.com

WindowsサービスとしてのASP.NET Coreのホスティング

RC2で入手したように、Windowsサービス内でアプリケーションをホストするためのサポートがあります。簡単なWeb APIプロジェクト(.NET Framework 4.6.1を使用)でテストしようとしました。

これが私のProgram.csコードです。

using System;
using System.IO;
using System.Linq;
using System.ServiceProcess;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Hosting.WindowsServices;

namespace WebApplication4
{
  public class Program : ServiceBase
  {
    public static void Main(string[] args)
    {
      if (args.Contains("--windows-service"))
      {
        Run(new Program());
        return;
      }

      var program = new Program();
      program.OnStart(null);
      Console.ReadLine();
      program.OnStop();
    }

    protected override void OnStart(string[] args)
    {
      var Host = new WebHostBuilder()
      .UseKestrel()
      .UseContentRoot(Directory.GetCurrentDirectory())      
      .UseStartup<Startup>()
      .Build();

      Host.RunAsService();
    }

    protected override void OnStop() {}
  }
}

他のすべてのものは基本的に.NET Coreテンプレートからのものです(ただし、フレームワークをnet461に変更し、project.jsonにいくつかの依存関係を追加しました)。

dotnet publishで公開し、sc createでWindowsサービスを作成した後、サービスを正常に開始できますが、コントローラーにアクセスできません(ポートが一覧表示されません)。私は何か間違ったことをしていると思います。

だから私は、主な質問は、自己ホスト型Web APIを作成し、それをWindowsサービスとして実行する方法だと思います。見つかったすべてのソリューションは、RC2更新後に機能しません。

31
Maria P

ここにはいくつかのオプションがあります-MicrosoftのWebHostServiceクラスを使用するか、WebHostServiceを継承するか、独自に作成します。後者の理由は、Microsoftの実装を使用すると、このクラスにはパラメーターなしのコンストラクターが含まれておらず、サービスロケーターにアクセスできないため、WebHostServiceを継承する型パラメーターを持つ汎用拡張メソッドを記述できないためです。

WebHostServiceを使用する

この例では、Microsoft.DotNet.Web.targetsを使用し、.exeを出力し、MVCアプリ(ビュー、コントローラーなど)として動作するコンソールアプリケーションを作成します。コンソールアプリケーションを作成し、.xproj内のターゲットを変更し、適切な公開オプションを持つようにproject.jsonを変更し、標準の.NET Core Webアプリテンプレートからビュー、コントローラー、webrootをコピーするのは簡単です。

ここで重要な部分:

  1. this パッケージを取得し、project.jsonファイルのフレームワークがnet451(またはそれ以降)であることを確認します

  2. エントリポイントのコンテンツルートがアプリケーションの.exeファイルの発行ディレクトリに適切に設定され、RunAsService()拡張メソッドが呼び出されることを確認してください。例えば:

    public static void Main(string[] args)
    {
        var exePath= System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName;
        var directoryPath = Path.GetDirectoryName(exePath);
    
        var Host = new WebHostBuilder()
            .UseKestrel()
            .UseContentRoot(directoryPath)
            .UseStartup<Startup>()
            .Build();
    
        if (Debugger.IsAttached || args.Contains("--debug"))
        {
            Host.Run();
        }
        else
        {
            Host.RunAsService();
        }
    }
    

.exeは、次のコマンドを使用して簡単にインストールできるようになりました。

    sc create MyService binPath = "Full\Path\To\The\Console\file.exe"

サービスが開始されると、Webアプリケーションがホストされ、そのビューが正常に検索およびレンダリングされます。

WebHostServiceを継承

このアプローチの主な利点の1つは、これによりOnStopping、OnStarting、およびOnStartedメソッドをオーバーライドできることです。

以下がWebHostServiceを継承するカスタムクラスであると仮定しましょう

internal class CustomWebHostService : WebHostService
{
    public CustomWebHostService(IWebHost Host) : base(Host)
    {
    }

    protected override void OnStarting(string[] args)
    {
        // Log
        base.OnStarting(args);
    }

    protected override void OnStarted()
    {
        // More log
        base.OnStarted();
    }

    protected override void OnStopping()
    {
        // Even more log
        base.OnStopping();
    }
}

上記の手順に従って、カスタムクラスを使用してホストを実行する独自の拡張メソッドを書き留める必要があります。

public static class CustomWebHostWindowsServiceExtensions
{
    public static void RunAsCustomService(this IWebHost Host)
    {
        var webHostService = new CustomWebHostService(Host);
        ServiceBase.Run(webHostService);
    }
}

エントリポイントの前の例から変更されずに残っている唯一の行は、最後のelseステートメントです。適切な拡張メソッドを呼び出す必要があります

Host.RunAsCustomService();

最後に、上記と同じ手順を使用してサービスをインストールします。

sc create MyService binPath = "Full\Path\To\The\Console\file.exe"
52
Ivan Prodanov

完全な.NET Frameworkのみで実行しても問題ない場合は、前の回答で十分です(ServiceBaseから継承するか、MicrosoftのWebHostServiceを使用します)。

ただし、。NET Coreのみで実行/実行したい場合(たとえば、Windows nanoサーバー、Linuxで通常のアプリとして動作する単一のバイナリ、 Windowsのサービスとして、またはシステムフレームワークを更新できないように古い.NET Frameworkバージョンのアプリと並行して実行する必要がある場合)、P/Invokesを介して適切なWindows API呼び出しを自分で行う必要があります。私はそれをしなければならなかったので、私は 正確にそれを行うライブラリ を作成しました。

sample が利用可能です。これは、管理者権限で実行したときに自身をインストールすることもできます(例:dotnet MyService.dll --register-as-service)。

9
Martin Ullrich

Microsoft.AspNetCore.HostingおよびMicrosoft.AspNetCore.Hosting.WindowsServicesを参照し、Startupクラスでこのコードを使用して、Windowsサービスとして実行可能にする必要があります。

public static void Main(string[] args)
{
    var Host = new WebHostBuilder()
                .UseIISIntegration()
                .UseKestrel()
                .UseContentRoot(@"Path\To\Content\Root")
                .UseStartup<Startup>()
                .Build();

    if (Debugger.IsAttached || args.Contains("--debug"))
    {
        Host.Run();
    }
    else
    {
        Host.RunAsService();
    }
}

次に、IWebHost.RunAsServiceの拡張メソッドを追加して、WebHostServiceおよびOnStoppingイベントハンドラーを含むカスタムOnStartingクラスでラップする必要があります。

public static class MyWebHostServiceServiceExtensions
{
    public static void RunAsMyService(this IWebHost Host)
    {
        var webHostService = new MyWebHostService(Host);
        ServiceBase.Run(webHostService);
    }
}

internal class MyWebHostService : WebHostService
{
    public MyWebHostService(IWebHost Host) : base(Host)
    {
    }

    protected override void OnStarting(string[] args)
    {
        base.OnStarting(args);
    }

    protected override void OnStarted()
    {
        base.OnStarted();
    }

    protected override void OnStopping()
    {
        base.OnStopping();
    }
}

この投稿 WindowsサービスでASP.NET Coreをホストする方法 とコメントが詳細をカバーしています。

UPDATE(詳細については ASP.NET Core 2.0の新機能の概要 )をご覧ください:

ASP.NET Core 1.1には次のようなものがあります。

public class Program
{
    public static void Main(string[] args)
    {
        var Host = new WebHostBuilder()
            .UseKestrel()
            .UseContentRoot(Directory.GetCurrentDirectory())
            .UseIISIntegration()
            .UseStartup<Startup>()
            .Build();

        Host.Run();
    }
}

ASP.NET Core 2.0では、次のようになります。

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

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

同様の問題の解決策を探しているときに、このトピックを見つけました。非常に(非常に)単純化されたTopshelfのように機能するものを実装することになりました。コンソールとして簡単に実行したり、インストールやアンインストールなどをサービスとして簡単に実行できます。誰かにとって非常に役立つと思います。ここでコードを見つけることができます: https://github.com/PeterKottas/DotNetCore.WindowsService そしてここにもナゲットがあります https://www.nuget.org/packages/PeterKottas.DotNetCore.WindowsService/ 。楽しい :)

2
Peter Kottas

Windowsサービスは、Visual Studio 2017で簡単に作成できます。NETCoreコードを、参照可能なNetStandardを対象とするクラスライブラリに移動する必要があります。 Windowsサービスプロジェクトは、完全な.NET Frameworkをターゲットにする必要がありますが、共有ライブラリを参照できます。

すべてのコードをクラスライブラリに配置すると、Windowsサービスと他のWindows以外のアプリとの間で移植性が得られます。

VS 2015では、Windowsサービスプロジェクトを作成し、.NET Core xprojを参照できませんでした。 Visual Studio 2017では、すべてのプロジェクトをcsprojに変換すると修正されます。

このブログでは、さらに詳しく説明します。 Visual Studio 2017で.NET Core Windowsサービスを作成する方法

2
Matt Watson

.netcoreチームのヘルパーメソッド内に実装されているように、appsettings.json、コマンド引数、ホストフィルタリングなどからの設定の読み取りを含む、ストックテンプレートをできるだけ多く使用して、.netcore 2.1に使用するものに合わせて更新しました。したがって、これらの設定の多くは、構成ファイルまたはコマンド引数を介して制御されます。ストックテンプレートが提供するものと、設定を上書きする方法に関するMicrosoftのドキュメントを確認してください。

Httpsとデフォルトの開発証明書を使用してエンドポイントを定義すると、サービスの開始に失敗することに注意してください。それは単に設定を介してpfxを指定することの問題かもしれません。誰かがこれを改善したい場合は、お気軽にそうしてください。

とにかく、私がprogram.csで使用するストックテンプレートコードです

public class Program
{
    public static void Main(string[] args)
    {

        if (args.Contains("--service"))
        {
            var path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
            Directory.SetCurrentDirectory(path); // need this because WebHost.CreateDefaultBuilder queries current directory to look for config files and content root folder. service start up sets this to win32's folder.
            var Host = CreateWebHostBuilder(args).Build();
            Host.RunAsService();
        }
        else
        {
            CreateWebHostBuilder(args).Build().Run();
        }

    }

    public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
        .UseStartup<Startup>();
}
1
AppLS

最新のVS2015 Update 2 ASP.NET Core Web Application(.NET Framework)テンプレートを使用し、以下のようにProgram.csのmodを使用すると、サービスとして、スタンドアロンで、VSで実行するときに正常に機能します。サービスとして実行する場合、wwwrootを含むディレクトリへのパスを設定する必要があることに注意してください。

これまでのところ、私はこのテンプレートとパターンが本当に好きです。 Visual Studioで通常どおりMVC6コードを開発し、サービスとしてクリーンに展開できます。実際、サービスのローカルインスタンスをテスト用に展開するときに、sc.exeを使用してサービスを削除/作成する必要がないことに気付きました。サービスを停止し、コードを発行してサービスを再起動するだけで、新しい変更が反映されます。

public class Program
{
    public static void Main(string[] args)
    {
        IWebHost Host = new WebHostBuilder()
            .UseKestrel()
            .UseContentRoot(Directory.GetCurrentDirectory())
            .UseIISIntegration()
            .UseStartup<Startup>()
            .Build();

        if (args.Contains("--windows-service"))
        {
            Host = new WebHostBuilder()
            .UseKestrel()
            .UseContentRoot("<directory-containing-wwwroot>")
            .UseIISIntegration()
            .UseStartup<Startup>()
            .UseUrls("http://+:5000")
            .Build();

            Startup.is_service = true;
            Host.RunAsService();
        }
        else
        {
            Host.Run();
        }
    }
}
1
howardlo