Goal
.NET Coreの起動処理の復習。主に、Configure回りを行う。
.NET での汎用ホスト
.NET での汎用ホストを読み込む。
導入
Worker サービス テンプレートを使用すると、.NET 汎用ホスト HostBuilder が作成されます。 汎用ホストは、コンソール アプリなど、他の種類の .NET アプリケーションで使用できます。
コンソールアプリケーションでも、汎用ホストを利用する。しっかりと公式ドキュメントに記載されていた。
ホストは通常、Program クラス内のコードによって構成、ビルド、および実行されます。
Programファイル内で、ホストオブジェクトの設定を行い、実行する。Windows Service用のプロジェクトテンプレートを選択した場合、ProgramファイルのほかにBackgroundServiceを継承したWorkerクラスが作成される。通常は、このWorkerクラスのRunメソッドを実装する。
public abstract class BackgroundService : IHostedService, IDisposable
BackgroundServiceは、IHostedServiceとIDisposableインターフェースを継承した抽象クラス。 似たようなことをしたい場合、IHostedServiceインターフェースを実装したクラスを用意することで実現することができる。
class Program :IHostedService { static void Main(string[] args) { Host.CreateDefaultBuilder().ConfigureServices(services => { services.AddHostedService<Program>(); }).Build().Run(); } public Task StartAsync(CancellationToken cancellationToken) { throw new NotImplementedException(); } public Task StopAsync(CancellationToken cancellationToken) { throw new NotImplementedException(); } }
[疑問]Runメソッドはどこで定義されている?
汎用HostをBuildした後、Hostクラスのインスタンスが戻されるが、Hostクラス自体には、Runメソッドは定義されていない。代わりに、HostingAbstractionsHostExtensions.cs クラスに拡張メソッドとして定義されている。これが呼ばれている。
[疑問]RunとStartの違い
Runメソッドのほかに、Startメソッドが定義されている。これらの違いは、XMLドキュメントから読み取れた。
Run: Runs an application and returns a Task that only completes when the token is triggered or shutdown is triggered. The instance is disposed of after running.
Start: Starts the host synchronously.
Runメソッドで開始された処理は、Host側(Windows Serviceとして考えたほうがよい?)が停止シグナルを受け取るまで動き続ける。Startメソッドは、処理が終われば、終了するという違いがある。
コンテナにデプロイしたコンソールアプリがずっと動き続けていた理由がわかった。。。Runしていたからだ・・・
builderの各種設定
規定のBuilder設定に詳細があるが、汎用ホストのDefaultBuilderを作成すると、appsettings.jsonや、プレフィックスにDOTNET_が付く環境変数、引数を読み込み、Key-Value形式でConfigurationに格納してくれる。
[疑問]コマンドライン引数もConfigurationに登録されるの?
詳しくは、CommandLineConfigurationProviderで定義されている処理を確認する。
- 利用できるオプション -, --, /
- 規定の動作(※key mapping利用しない場合)
-key value -> ignore
If the switch starts with a single "-" and it isn't in given mappings , it is an invalid usage so ignore it
-key=value -> FormatException!
If the switch starts with a single "-" and it isn't in given mappings , it is an invalid usage
--key value -> mapped
--key=value -> mapped
/key value -> mapped
/key=value -> mapped
value -> ignore
key=value -> mapped
- これも可
- key value -> ignore
- これは不可
- 規定の動作(※key mapping利用しない場合)
※Keyの後ろに、Valueがない場合は、すべて無視される。 ※key mappingを利用すれば、さらに柔軟なマッピング処理を定義可能
mappingされた引数は、Configuration.GetSection("key").Value
で取得することができる。
なお、Key-Value配列では、StringComparer.OrdinalIgnoreCaseオプションが付けられているため、Keyの大文字小文字を意識しなくて良い。
new Dictionary<string, string?>(StringComparer.OrdinalIgnoreCase);
[メモ]引数の取得
private readonly string _arg1; public Program(IConfiguration configuration) { _arg1 = configuration.GetSection("key1").Value; }