SAKURUG TECHBLOG

ASP.NET Coreにおける汎用ホストの提供する機能について

timestampauthor-name
Tomomitsu

汎用ホストとは?

ASP.NET Coreにおける汎用ホスト(Generic Hosts)とは以下のようなアプリのリソースをカプセル化し便利に使えるようにするオブジェクトです。

特に、ASP.NET Coreでは事実上のエントリーポイントとなっています。

  • 依存関係の挿入(DI)
  • ログの記録
  • 構成
  • IHostedServiceの実装

汎用ホストのコード例

以下の例は汎用ホストを使い、Hello Worldを表示するWebアプリケーションを構築した例です。

var app = WebApplication.Create(args);
app.MapGet("/", () => "Hello World!");
app.Run();

WebApplicationでは条件に応じて次のミドルウェアが自動的に追加されます。

  • UseDeveloperExceptionPageはHostingEnvironmentが”Development”である場合最初に追加されます。これによって、開発環境で同期例外と非同期例外をキャプチャーし、エラー応答を生成します。
  • UseRoutingはユーザによってUseRoutingが呼び出されておらず、エンドポイントが構成されている場合(MapGetなどなんらかのURLで呼び出しがある場合)2番目に追加されます。
  • UseEndpointsはエンドポイントが構成されている場合、パイプラインの最後に構成されます。
  • UseAuthenticationはサービスプロバイダーでIAuthenticationSchemeProviderが検出された場合、UseRoutingの直後に追加されます。
  • UseAuthorizationはサービスプロバイダーでIAuthorizationHandlerProviderが検出された場合、次に追加されます。

Createでは次のタスクが自動的に実行されます。

  • ホスティング構成プロバイダーを使用してKestrelサーバをWebサーバとして構成します。
  • コンテンツルートを、Directory.GetCurrentDirectoryによって返されるパスに設定します。
  • 次からホスト構成を読み取ります。
  • ASPNETCORE_のついた環境変数
  • コマンドライン引数
  • 次の順序で構成を読み取ります
  • appsettings.json
  • appsettings.{Environment}.json
  • ユーザーシークレット
  • 環境変数
  • コマンドライン引数
  • コンソールとデバッグ出力のログを構成します。
  • ASP.NET Coreモジュールを使用してIISと連携して実行されている場合はアプリのベースアドレスとポートが構成されるIISの統合が有効になります。

依存関係の挿入(DI)について

ASP.NET Coreでは依存関係の挿入(DI)が汎用ホストによってサポートされています。依存関係とは他のオブジェクトが依存するオブジェクトのことです。

ここでは、WriteMessageというメソッドを備えたMyDependencyというクラスについて調べてみます。

public class MyDependency
{
    public void WriteMessage(string message)
    {
        Console.WriteLine($"MyDependency.WriteMessage called. Message: {message}");
    }
}

MyDependencyクラスのインスタンスを作成してそのWriteMessageメソッドを使用することができます。

public class IndexModel : PageModel
{
    private readonly MyDependency _dependency = new MyDependency();


    public void OnGet()
    {
        _dependency.WriteMessage("IndexModel.OnGet");
    }
}

このクラスはMyDependencyクラスを作成しこれに直接依存しています。

これは、次のような問題点があります。

  • MyDependencyを別の実装で置き換えるためにはIndexModelクラスを置き換える必要がある
  • MyDependencyが依存関係を含んでいる場合はIndexModelクラスによって構成する必要がある
  • 複数のクラスがMyDependencyに依存している大規模なプロジェクトでは構成コードがアプリ全体に分散する
  • 単体テストを行うことが困難

依存関係の挿入は次の方法でこれらの問題に対処します。

  • 依存関係を抽象化するためのインターフェースまたは基底クラスの使用。
  • サービスコンテナ内の依存関係の登録。
  • ASP.NET Coreでは、組み込みのサービスコンテナであるIServiceProvicerが用意されています。
  • サービスを使用するクラスへのコンストラクタへのサービスの挿入、依存関係のインスタンスの作成、およびインスタンスが不要になったときの廃棄の役割を汎用ホストが行います。

ログの記録

既定のテンプレートでは次のログプロバイダーが追加されます。

  • コンソール
  • デバッグ
  • EventSource
  • EventLog(Windowsのみ)

ログを作成する

ログを作成するには依存関係の挿入からILogger<TCategoryName>オブジェクトを使用します。

public class AboutModel : PageModel
{
    private readonly ILogger _logger;


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


    public void OnGet()
    {
        _logger.LogInformation("About page visited at {DT}", 
            DateTime.UtcNow.ToLongTimeString());
    }
}

構成

汎用ホストによって起動時に構成情報を読み取り実行されます。

以下のような様々な構成ソースを使用してキーと値ペアから構成データを読み取ります。これによって実行環境によって構成情報を変化させるということを実現できます。

また、構成情報を読み取る優先順位が設定されていますのでより優先順が高い構成情報でオーバーライドさせるといったことができます。

例えば、ローカル開発時にはappsettings.jsonなどの設定ファイルで構成情報を設定していたが本番環境ではAzure Key VaultやAzure App Configurationなどより優先順位の高い構成情報でオーバーライドすることができます。

以下のソースから構成データを読み取ります

  • appsettings.jsonなどの設定ファイル
  • 環境変数
  • Azure Key Vault
  • Azure App Configuration
  • コマンドライン引数
  • インストール済みカスタムプロバイダー
  • ディレクトリーファイル
  • メモリ内.NETオブジェクト

IHostedServiceの実装

汎用ホストを起動すると、サービスコンテナのホステッドサービスのコレクションに登録されているIhostedServiceの実装でIHostedService.StartAsyncが呼び出されます。

さらに、ホストが正常なシャットダウンを実行しているときにIHostedService.StopAsyncが呼び出されます。通常、このメソッドの中でタスクを終了するロジックやアンマネージドリソースを破棄するロジックを記述します。

これにより、アプリケーションのシャットダウンを安全に行うことができます。

ASP.NET Coreにおいてのユースケースとしてはバックグラウンドサービスを実装するケースです。

ミドルウェア

ASP.NET Coreには組み込みで多くのWebシステムで使われるであろうミドルウェアが用意されています。

  • 認証
  • 承認
  • CORS
  • 診断
  • 正常性チェック
  • HTTPログ
  • HTTPSリダイレクト
  • MVC
  • 出力キャッシュ
  • 応答キャッシュ
  • エンドポイントルーティング
  • SPA
  • セッション
  • 静的ファイル
  • URL書き換え
  • W3CLogging
  • WebSocket


記事をシェアする

ABOUT ME

author-image
Tomomitsu
2017年2月中途入社。業務ではAzureへのモダナイゼーションを行っています。Microsoft MVP for Developer Technologies 2022 -