C#入門編(26)HostApplicationBuilderでC#アプリの土台を作る【設定・DI・ログ統合】
C#入門編です。今回はC#における「Host(ホスト)」について解説します。
「設定管理、DI、ロギング…それぞれは理解できたけど、毎回組み立てるのが大変」と感じていませんか?
本記事は以下の方に役立つ内容となっています。
- 設定・DI・ロギングを統合的に扱いたい方
- HostApplicationBuilderの使い方を学びたい方
- モダンなC#アプリの構成パターンを身につけたい方
Hostは、これまで学んできた設定管理・DI・ロギングを「一つの基盤」として統合する仕組みです。
今回は、C#モダン開発における構成要素の最後のピース「Host」を学び、これまでの知識を総まとめします。
- 設定管理:appsettings.jsonとIConfigurationで設定を外部化
- DI(依存性注入):依存関係を外から渡す設計手法
- ログ:ILoggerによる構造化ログ
- Host:設定・DI・ログを統合するアプリの骨格(←今回紹介!)
Hostを使うと、これまで手動で組み立てていた「設定読み込み → DIコンテナ構築 → ロギング設定」を、簡潔に記述できます!
以下の設定管理・DI・ロギングに関する記事をあらかじめ見ておいてもらえると、より理解が深まるかと思います。
演習コードをGitHubで公開してます。
動画も作成しています。
https://www.youtube.com/watch?v=kgx1UpXTDNI
講義1:Hostとは
なぜHostは必要か
これまでの入門編で、以下の技術を個別に学んできました。
- 設定管理:
IConfigurationで複数の設定ソースから設定値読み込み - DI:
ServiceCollectionでDIコンテナを構築する - ロギング:
ILoggerとLoggerFactoryでログを出力する
これまで学んできたように、設定ファイル、DI、ロギングを行うコードは以下のようなりますが、これらは定型的なコードであり毎回手動で書くのは手間がかかります。
// 設定の読み込み
IConfigurationRoot configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json") //設定ファイル
.AddCommandLine(args) //実行時引数
.Build();
// DIコンテナの設定
ServiceCollection services = new ServiceCollection();
services.AddLogging(builder =>
{
builder.AddConsole();
});
services.AddSingleton<IConfiguration>(configuration);
services.AddTransient<MyService>();
using ServiceProvider provider = services.BuildServiceProvider();
provider.GetRequiredService<MyService>().Run();加えて、実際のアプリ開発では、これに加えて以下も必要です。
- 環境(Development/Production)に応じて設定を切り替える
- アプリのライフサイクル(起動・終了)を管理する
このような定型的なコードを毎回ゼロから書くのは非効率ですし、書き方がプロジェクトごとにバラバラになりがちです。
たしかに、設定・DI・ロギングの初期化コードって、どのプロジェクトでも似たようなことを書いてる気がする…
Hostが提供するもの
Host(ホスト) は、.NETアプリの「骨格」を提供する仕組みです。以下の機能が統合されています。
| 機能 | 説明 |
|---|---|
| 設定管理 | appsettings.jsonや環境変数を自動読み込み |
| DI | サービスの登録と解決を行うDIコンテナ |
| ロギング | ILoggerを使ったログ出力基盤 |
| 実行環境切り替え | Production/Development等の切り替え |
| ライフサイクル管理 | アプリの起動・終了を制御 |
Hostを使うと、これらの初期化が数行で完了し、すぐにアプリのロジックに集中できます。
さきほど例示したコード相当は以下のように短く書けます。(正確には、よく使う標準的な構成を自動で用意してくれています。)
// Hostを使った場合
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Services.AddTransient<MyService>();
using IHost host = builder.Build();
// ↑ appsettings.json読み込み、コンソールロギング、DIコンテナが全部セットアップ済み!
host.Services.GetRequiredService<MyService>().Run();たったこれだけで、設定・DI・ロギングがすべて使える状態になります。
それでは、次にもう少し詳しくこの「HostApplicationBuilder」と「IHost」の使い方をみていきましょう。
講義2:HostApplicationBuilder、IHostの使い方
HostApplicationBuilderの基本
Host.CreateApplicationBuilder()で取得できるHostApplicationBuilderには、以下のプロパティがあり、DIコンテナへの登録・ロギングの設定などを行えます。
| プロパティ | 型 | 用途 |
|---|---|---|
Services | IServiceCollection | DIコンテナへのサービス登録 |
Configuration | ConfigurationManager(IConfigurationを実装) | 設定の読み込み・追加 |
Environment | IHostEnvironment | 実行環境の情報 |
Logging | ILoggingBuilder | ロギングの設定 |
HostApplicationBuilderでは、設定の読み込み、ロギング、DIコンテナへのサービス登録について、標準的なセットが事前に用意されています。
設定の読み込み
基本
Host.CreateApplicationBuilder()は、以下のアプリの設定ソースを自動で読み込みます。
| 順序 | 設定ソース | 補足 |
|---|---|---|
| 1 (優先度は最低) | appsettings.json | 共通設定 |
| 2 | appsettings.{Environment}.json | 環境別設定(例:appsettings.Development.json) |
| 3 | ユーザシークレット | Development環境のみ。APIキーなど機密情報用 |
| 4 | 環境変数 | |
| 5 (優先度は最高) | コマンドライン引数 |
例えば、以下のようなappsettings.jsonを配置しておくと、
{
"ApiSettings": {
"BaseUrl": "https://api.example.com",
"TimeoutSeconds": 30
}
}以下のようにプログラムで設定値を読み込むことができます。
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
// 設定値を取得(自動で読み込まれている)
string? baseUrl = builder.Configuration["ApiSettings:BaseUrl"];
Console.WriteLine($"API URL: {baseUrl}"); // "https://api.example.com"を出力また、DIコンテナへ自動でIConfigurationが登録されるため、以下のように各サービスクラスで参照することもできます。
public class MyService
{
private readonly IConfiguration _configuration;
public MyService(IConfiguration configuration)
{
_configuration = configuration;
// _configurationを使って設定値を読み込み可能
}「設定値読み込み」の標準的な構成の作成とDIコンテナへの登録を、自動でやってくれるんだね!
環境の切り替え
実行環境(Development/Production等)は、環境変数「DOTNET_ENVIRONMENT」で指定します。例えば、PowerShellなら以下です。
$env:DOTNET_ENVIRONMENT = "Development"例えば「Development」を指定すると、「appsettings.json」に加えて「appsettings.Development.json」も読み込まれ、同じキーがあれば上書きされます。
プログラム内で現在の環境を確認するには、「builder.Environment」を使います。
Console.WriteLine(builder.Environment.EnvironmentName); Visual Studioでは、プロジェクトのプロパティ→デバッグ→環境変数で設定できます。launchSettings.jsonに保存されます。
ロギングの設定
Host.CreateApplicationBuilder()は、以下のログプロバイダーを自動で登録します。
| プロバイダー | 説明 |
|---|---|
| Console | コンソールへの出力 |
| Debug | デバッグ出力 (Visual Studioの出力ウィンドウなど) |
| EventSource | 診断・監視ツールから購読するための出力先(通常は画面には表示されない) |
つまり特に何も設定しなくても、ILogger<T>を使ったログ出力が「コンソール、デバッグ出力」に表示されます。
また、ロギング機能を使うためのDIコンテナへの各種登録も自動で行われるため、以下のようにサービスクラスでロギング機能を利用可能です。
public class MyService
{
private readonly ILogger<MyService> _logger;
public MyService(ILogger<MyService> logger)
{
_logger = logger;
}
public void DoWork()
{
_logger.LogInformation("処理を実行しました"); // コンソールに出力される
}
}設定値と同じで、ロギングについても標準的な構成の作成とDIコンテナへの登録を自動で行ってくれるんだね!
HostApplicationBuilderにおける設定自動読み込み・自動ロギング設定についての詳細はMicrosoft Learnの記事も参考にしてください。
ライフサイクル管理 ~IHostedServiceの使い方~
Hostの重要な役割の1つとして、アプリのライフサイクル管理もあります。
IHostedServiceインターフェースを実装したサービスを登録すると、Hostが起動・終了を管理してくれます。
例えばBackgroundServiceは、IHostedServiceを実装したバックグランド実行アプリ向けの基底クラスで、以下のように使います。
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
// ↓IHostedServiceとして登録(Singletonとして登録され、Hostが起動・終了を管理)
builder.Services.AddHostedService<MyService>();
IHost host = builder.Build();
await host.RunAsync();
public class MyService : BackgroundService
{
private readonly ILogger<MyService> _logger;
public MyService(ILogger<MyService> logger)
{
_logger = logger;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
_logger.LogInformation("サービス開始");
// 何らかの処理(ここでは3秒待機)
await Task.Delay(3000, stoppingToken);
_logger.LogInformation("サービス終了");
}
}これを実行すると以下のように出力されます。このプログラムはExecuteAsyncが完了しても、Ctrl+Cが押されるまで待機し続けます。
info: Microsoft.Hosting.Lifetime[0]
Application started. Press Ctrl+C to shut down.
info: MyService[0]
サービス開始
info: Microsoft.Hosting.Lifetime[0]
Hosting environment: Production
info: Microsoft.Hosting.Lifetime[0]
Content root path: D:\data\projects\00apps\ConsoleApp1\ConsoleApp1\bin\Debug\net10.0
info: MyService[0]
サービス終了(「Microsoft.Hosting.Lifetime」となっているログはHostが出力したものです。)
host.RunAsync()を呼ぶと、Hostは以下を行います。
- 登録された
IHostedServiceをすべて起動 - Ctrl+Cが押されるまで待機(サービス側で全体を終了させることも可能)
- シャットダウン時に
IHostedServiceを安全に停止(グレースフルシャットダウン)
CancellationTokenを使うと、Ctrl+Cが押されたときに処理を中断可能です。これがHostによる「グレースフルシャットダウン」の仕組みです。
なるほど!Hostを使うと「起動・実行・終了」をHostが面倒見てくれるんだね。
補足:ASP.NET CoreやMAUIにおけるHost
今回学んだHost.CreateApplicationBuilder()は、汎用のHostを作るためのものです。
実は、ASP.NET CoreやMAUIにもそれぞれに特化したビルダーがあり、基本的な使い方は共通しています。
| ビルダー | 用途 |
|---|---|
Host.CreateApplicationBuilder() | 汎用 |
WebApplication.CreateBuilder() | ASP.NET Core Webアプリ |
MauiApp.CreateBuilder() | .NET MAUIアプリ |
いずれもbuilder.ServicesでDI登録、builder.Configurationで設定取得…という同じパターンです。
今回学んだHostの知識は、ASP.NET CoreやMAUIでもそのまま活かせます。
「設定・DI・ロギングの統合基盤」という考え方は.NETアプリ共通のパターンなのです。
演習:設定・DI・ロギングをHostで統合しよう
これまで学んできた設定管理・DI・ロギングを、Hostで統合してみましょう。前回のDataServiceとApiClientを使った演習コードを追加・修正し、以下の構成を実現します。
- 設定:appsettings.jsonからAPI接続先を読み込む
- DI:ApiClient、DataServiceをDIコンテナに登録
- ロギング:Serilogでコンソールとファイルに出力
最終的には以下の構成になります。

それでは前回演習コードをベースに作成していきましょう!
手順1:パッケージ追加
以下のパッケージを追加します。
- Microsoft.Extensions.Hosting
手順2:設定ファイルと設定用クラスを追加
以下のappsettings.jsonを追加します。
{
"ApiSettings": {
"BaseUrl": "https://api.example.com",
"TimeoutSeconds": 15
}
}
また、このApiSettingsに対応するクラス(ApiSettings.cs)も追加します。(Optionパターンにより設定値をマッピングします)
namespace DISample;
public class ApiSettings
{
// デフォルト値は設定漏れ時のフォールバック
public string BaseUrl { get; set; } = "";
public int TimeoutSeconds { get; set; } = 30;
}
また、appsettings.jsonが実行時に参照できるようにするため、プロジェクトファイルへ以下のように<ItemGroup>を追記しましょう。
<Project Sdk="Microsoft.NET.Sdk">
...
<ItemGroup>
<None Update="appsettings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
「C#入門編(23):モダンなC#の設定管理」の演習でも、この設定はしていたね!
手順3:Programを修正
以下のように、Program.csを修正します。Hostを使って、ログ設定、設定読み込み、DIコンテナへのサービス登録を行っています。
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Serilog;
using DISample;
// 0. Serilogの設定
// 出力先、フォーマット、ログレベルなどを指定
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Information()
//↓ Hosting.LifetimeのログレベルをWarningに上げて冗長な情報を抑制
.MinimumLevel.Override("Microsoft.Hosting.Lifetime", Serilog.Events.LogEventLevel.Warning)
.Enrich.WithMachineName()
.WriteTo.Console(outputTemplate:
"[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}")
.WriteTo.File("logs/app-.log",
rollingInterval: RollingInterval.Day,
outputTemplate:
"{Timestamp:yyyy-MM-dd HH:mm:ss.fff} [{Level:u3}] [Machine: {MachineName}] {Message:lj}{NewLine}{Exception}")
.CreateLogger();
// 1. HostApplicationBuilderを作成
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
// 2. Serilogを使用するように設定(既存のLog.Logger設定を使用)
builder.Logging.ClearProviders(); // 既存のロギングプロバイダーをクリア
builder.Logging.AddSerilog(dispose: true);
// 3. 設定をバインド(appsettings.jsonから自動読み込み)
// これでIOptions<ApiSettings>がDIコンテナに登録される
builder.Services.Configure<ApiSettings>(
builder.Configuration.GetSection("ApiSettings"));
// 4. サービスを登録
// ここでMockApiClientに変更すれば、実装を簡単に差し替えられる
builder.Services.AddTransient<IApiClient, ApiClient>();
// 5. DataServiceをHostedServiceとして登録
builder.Services.AddHostedService<DataService>();
// 6. ホストをビルドして実行
IHost host = builder.Build();
await host.RunAsync();Hostが裏で色々な設定を行ってくれているので、コンポジションルート(Program.cs)のコードはこのように比較的シンプルになります。
「3.設定をバインド」では、Optionパターンを使っています。これを使うと、設定ソースの値をクラスへバインドし、DIで各サービスへ注入可能になります。
Optionパターンでは、設定値のバリデーションや設定値の再読み込みなど様々な機能があります。詳しくはMicrosoftの記事を参考にしてください。
手順4:ApiClient、DataServiceクラスを修正
ApiClient.csを以下のように修正します。
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
namespace DISample;
public class ApiClient : IApiClient
{
private readonly ApiSettings _settings;
private readonly ILogger<ApiClient> _logger;
public ApiClient(IOptions<ApiSettings> options, ILogger<ApiClient> logger)
{
_settings = options.Value;
_logger = logger;
}
public string GetData()
{
_logger.LogDebug("APIリクエスト開始: {BaseUrl}", _settings.BaseUrl);
// 実際のアプリではHttpClientを使ってAPI呼び出し
return $"[{_settings.BaseUrl}] からデータ取得(タイムアウト: {_settings.TimeoutSeconds}秒)";
}
}
コンストラクタの「IOptions<ApiSettings> options」で、DIコンテナへ登録された設定値クラスが注入されます。
DataService.csを以下のように修正します。DataServiceはBackgroundServiceを継承させて、IHostedServiceとして振舞えるようにします。
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
namespace DISample;
public class DataService : BackgroundService
{
private readonly IApiClient _client;
private readonly ILogger<DataService> _logger;
public DataService(IApiClient client, ILogger<DataService> logger)
{
_client = client;
_logger = logger;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
_logger.LogInformation("データ取得処理を実行します");
var data = _client.GetData();
_logger.LogDebug("APIからのレスポンス: {Response}", data);
Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] 取得結果: {data}");
_logger.LogInformation("データ取得処理が正常に完了しました");
await Task.CompletedTask;
}
}
「builder.Services.AddHostedService<DataService>()」って、コンポジションルートで登録されていたね。
だから、host.Run()でDataServiceの「ExecuteAsync」が実行されるんだ!
アプリを実行
アプリを実行すると以下のように出力され、終了を待機する状態になり、そのあとCtrl+Cで終了します。(ログがファイルとしても出力されています)
[12:40:05 INF] データ取得処理を実行します
[12:40:05] 取得結果: [https://api.example.com] からデータ取得(タイムアウト: 15秒)
[12:40:05 INF] データ取得処理が正常に完了しましたHostを使ったアプリが動いた!これで、設定・DI・ロギングが備わったC#アプリ開発の骨組みはばっちりだね!
そうですね。これがC#のモダンなアプリ開発の土台です!
環境種別(Production/Development)変更による設定ファイルの切り替えなども試してみると、より理解が深まるかと思います。
ちなみに、DataServiceのExecuteAsyncが終了したらアプリ全体を終了させたい場合は、以下のようにIHostApplicationLifetimeを使います。
public class DataService : BackgroundService
{
...
private readonly IHostApplicationLifetime _lifetime;
public DataService(..., IHostApplicationLifetime lifetime)
{
...
_lifetime = lifetime;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
...
_lifetime.StopApplication(); //アプリ全体を終了
await Task.CompletedTask;
}
}IHostApplicationLifetimeはデフォルトでDIコンテナに登録されています。
まとめ
今回はHostについて学びました。
Hostとは、設定管理・DI・ロギング・ライフサイクル管理を統合する「アプリの骨格」です。これまで手動で組み立てていた初期化の定型コードを大きく削減できます。
BackgroundService(IHostedService)を使うと、Hostがサービスのライフサイクル(起動・終了)を管理してくれます。
演習では、これまで学んできた設定管理・DI・ロギングをHostで統合し、ライフサイクル管理についてはBackgroundServiceを使った実践的なアプリを作成しました。
これで、モダンC#アプリの基盤となる4つの柱「設定管理・DI・ロギング・Host」をすべて学び終えました!
引き続き、一緒にC#プログラミングについて学んでいきましょう。






