オリジナル:サービスシステムベアラ[コアASP.NETフレームワーク3覆われていない。] [5]:ベアラサービスの起動プロセス〔パートI〕
「で我々全体的な設計第I部」と「全体的なデザイン、[次へ]を 3つのインタフェースは、読者がサービスモデルの友人に運ぶことができIHostedService、IHostとIHostBuiderの導入までは、」一般的な理解を持っています。次に、我々はモデルの実現のためのシステムを運んで見て、抽象から具象に回すことはどのように着陸です。達成するために、デフォルトベアラのモデルを理解するにはそれだけのインターフェイスおよびデフォルトIHost IHostBuilderの実装タイプを理解する必要があります。以下に示すUMLからわかるように、これら2つのタイプのインタフェースのデフォルトの実装では、ホストされているとHostBuilderは、Benpianは両方のタイプをハイライト表示されます。「ASP.NETコア3の枠組みの復号化」今後の本から、この部分の抜粋では、興味のある友人ができる「」ASP.NETコア3の枠組みの秘密「の読者は、」へようこそ書籍リーダーに参加します
まず、サービスホスト
ホストインターフェイスのIHost実装のデフォルトのタイプである私達はがちで、このセクションでは、同じ名前の最後に伴う公共の静的なタイプになりますので、それは、内部NuGetパッケージ「Microsoft.Extensions.Hosting」のタイプの単なる定義です混乱の、我々は違いを示すために、「インスタンスタイプホスト」、それを呼び出します。ホストタイプの正式なプレゼンテーションを実現する前に、我々は二つの関連種類、ベアラ設定オプションを関連HostOptionsとなっているものを理解することが最初のを持っています。次のコードは、HostOptionsはshutdownTimeoutには、そのデフォルト値は5秒閉じホストオブジェクトのタイムアウトであることを意味するユニークな属性が含まれています。
パブリッククラスHostOptions { 公共のTimeSpan shutdownTimeoutに{取得します。セットする; } = TimeSpan.FromSeconds(5)。 }
我々が「全体的な設計〔パートI]が」IHostApplicationLifetimeインターフェースライフサイクルベアラ関連アプリケーションを満たしている、ホストはのライフサイクルに関連する別のタイプに関するIHostLifetimeのインターフェース。私たちは、ホストオブジェクトStartAsyncメソッドを呼び出すと、それは最初WaitForStartAsync方法IHostLifetimeサービスを呼び出すなる、開始します。それが成功したすべてのホスティングサービスを閉鎖した場合、実装工程におけるStopAsyncホストオブジェクトメソッドは、登録サービスStopAsync IHostLifetimeメソッドが呼び出されたとき。
パブリックインターフェースIHostLifetime { タスクWaitForStartAsync(CancellationToken cancellationToken)。 タスクStopAsync(CancellationToken cancellationToken)。 }
「で、[次へ]長時間実行ベアラサービスログデモプログラムの時間」を、プログラムが最初のログは、アプリケーションが起動」だったの内容は、コンソールログレベルの情報に、3つの出力後に開始されます。Ctrlキーを押し+ Cは、シャットダウンします。」、ルートディレクトリとストアのコンテンツファイルの現在の搬送路の出力環境情報である2を。アプリケーションが閉じられる前に、コンソールの「アプリケーションがシャットダウンしている...」ログというメッセージが表示されます。次の図に反映コンソール効果上の4以上の対数スケール出力。
上記示された4件のログが目標ConsoleLifetimeとして出力され、ConsoleLifetimeはIHostLifetime型インタフェースを達成します。ログの形式以外の電流搬送アプリケーションに関連付けられた出力状態情報に加え、次いで、キャンセルキー(Ctrlキー+ C)、のための捕獲及び通電閉じ機能もConsoleLifetime型に実装されています。ConsoleLifetimeOptionsで定義さConsoleLifetime構成オプションは、固有の属性メンバーの種類は4 SuppressStatusMessagesを出力するログか否かを決定するために使用され、使用されるタイプ。
パブリッククラスConsoleLifetime:IHostLifetime、IDisposableを { 公共ConsoleLifetime(IOptions <ConsoleLifetimeOptions>オプション、IHostEnvironment環境、IHostApplicationLifetime applicationLifetime)。 公共ConsoleLifetime(IOptions <ConsoleLifetimeOptions>オプション、IHostEnvironment環境、IHostApplicationLifetime applicationLifetime、ILoggerFactory loggerFactory)。 パブリックタスクStopAsync(CancellationToken cancellationToken)。 パブリックタスクWaitForStartAsync(CancellationToken cancellationToken)。 公共のボイドのDispose(); } パブリッククラスConsoleLifetimeOptions { パブリックブールSuppressStatusMessages {GET。セットする; } }
次のコードは、簡略化ホスト・タイプの定義を示します。ホスト型のコンストラクタ依存性注入依存性注入コンテナとして含む一連のサービス、IServiceProviderのログインするためのオブジェクトILoggerです<ホスト>オブジェクトをし、提供するオプションのIOptions <HostOptions>オブジェクト、および2つのライフサイクルと関連IHostApplicationLifetimeは、オブジェクトとIHostLifetimeはオブジェクト。それはタイプがここにIHostApplicationLifetimeオブジェクトを必要とすることを言及する価値があることは、それはアプリケーションの起動とシャットダウン後の加入者に通知するために、そのNotifyStartedとNotifyStoppedメソッドを呼び出す必要があるため、ApplicationLifetimeであるが、これらの方法は、インタフェースIHostApplicationLifetimeで定義されていませんインチ
内部クラスのホスト:IHost { プライベート読み取り専用ILoggerです<ホスト> _logger。 プライベート読み取り専用IHostLifetime _hostLifetime。 プライベート読み取り専用ApplicationLifetime _applicationLifetime。 プライベート読み取り専用HostOptionsの_options。 民間のIEnumerable <IHostedService> _hostedServices。 公共IServiceProviderサービス{取得します。} パブリックホスト(IServiceProviderサービス、IHostApplicationLifetime applicationLifetime、ILoggerです<ホスト>ロガー、IHostLifetime hostLifetime、IOptions <HostOptions>オプション) { サービス=サービス。 _applicationLifetime =(ApplicationLifetime)applicationLifetime。 _logger =ロガー。 _hostLifetime = hostLifetime。 _options = options.Value)。 } タスクStartAsync(CancellationToken cancellationToken =デフォルト)非同期公衆 { のawait _hostLifetime.WaitForStartAsync(cancellationToken)。 cancellationToken.ThrowIfCancellationRequested(); _hostedServices = Services.GetService <IEnumerableを<IHostedService >>(); foreachの(_hostedServicesでのvar hostedService) { のawait hostedService.StartAsync(cancellationToken).ConfigureAwait(偽)。 } _applicationLifetime .NotifyStarted();? } パブリック非同期タスクStopAsync(CancellationToken cancellationToken =デフォルト) { (VARのCTS =新しいCancellationTokenSource(_options.ShutdownTimeout))を使用して (VAR linkedCts = CancellationTokenSource.CreateLinkedTokenSource(cts.Token、cancellationToken))を使用して、 { VARトークン= linkedCts.Token。 _applicationLifetime .StopApplication();? foreachの(_hostedServices.Reverse()内のvar hostedService) { のawait hostedService.StopAsync(トークン).ConfigureAwait(偽)。 } token.ThrowIfCancellationRequested()。 await _hostLifetime.StopAsync(トークン)。 _applicationLifetime .NotifyStopped();? } } 公共のボイドのDispose()=>(IDisposableインターとしてサービス)?。廃棄(); }
StartAsyncでホストオブジェクトがWaitForStartAsync IHostLifetimeオブジェクトと呼ばれる方法を開拓し、実装。ConsoleLifetimeのためのサービス登録のタイプならば、それは出力3は、前述のログに記録されます。一方、ConsoleLifetimeコンソールオブジェクトは、キーイベントを登録し、その目的は、ユーザが押したときに正常に閉じられるようにキーの組み合わせ(Ctrlキー+ C)アプリケーションを取り消すことを保証することです。
ホストは、すべてのIHostedServiceベアラサービスを表す抽出されたオブジェクトIServiceProviderコンテナオブジェクトの依存関係を使用してオブジェクト、及びStartAsync法によってそれらを開始します。すべてのベアラサービスが正常に起動すると、NotifyStarted方法ApplicationLifetimeオブジェクトが呼び出され、この時点の加入者は、通知アプリケーションが起動されます。ことに注意することが重要な一つのこと:「一つ一つ(ない同時)」ベアラサービスを表すすべてのIHostedServiceオブジェクトがあるが活性化され、唯一のすべてのベアラサービスがすべて開始したのを待って、私たちのアプリケーションが成功するために始めました。起動プロセスの全体にわたって、CancellationToken解除要求が受信されたパラメータとして使用される場合の動作アボートを開始します。
StopAsyncホストオブジェクトのメソッドが呼び出されると、それは外部の通知アプリケーションのApplicationLifetimeオブジェクトStopApplicationメソッドを呼び出します。それは、各IHostedServiceオブジェクトのStopAsyncメソッドを呼び出しますされた後、閉鎖されようとしています。すべてのベアラサービスが正常に閉じられたときNotifyStopped方法は、ホスト・オブジェクトはIHostLifetimeオブジェクトStopAsyncとApplicationLifetimeオブジェクトを呼び出す必要があります。タイムアウトがHostOptions設定オプションを超えている場合、ホストのクローズ処理では、キャンセル要求はCancellationTokenパラメータを受信したりして、プロセスが中止されます。
第二に、システムを構成するための設定
サービスIHostのターゲットホストが対応するIHostBuilderて建物の外に常にあるようIHostBuilderタイプの実現に対応するタイプのホスト上でオブジェクトHostBuilder我々はHostBuilderホストオブジェクトは、オブジェクトが出て構築されている方法を模索しようとしている横、。IHostオブジェクトを構築するビルド方法に加えて、我々は適切な事前設定された目標IHost最終申し出をすることができるようにIHostBuilderインタフェースはまた、一連のメソッドを定義し、これらの設定は、最終的にはビルド方法に適用されるキャッシュされます。
システムの構成のためのHostBuilder設定でのスタートをしてみましょう。次のコード断片、ConfigureHostConfigurationのホストコンフィギュレーションのための方法および配向ConfigureAppConfigurationのデリゲートオブジェクト指向のアプリケーションを一時的にオブジェクトの対応するセットに保存されている方法を提供するように構成されている、対応するフィールドはconfigureHostConfigActionsとconfigureAppConfigActionsあります。
パブリッククラスHostBuilder:IHostBuilder { プライベートリスト<アクション<IConfigurationBuilder >> _configureHostConfigActions =新しいリスト<アクション<IConfigurationBuilder >>(); プライベートリスト<アクション<HostBuilderContext、IConfigurationBuilder >> _configureAppConfigActions =新しいリスト<アクション<HostBuilderContext、IConfigurationBuilder >>(); 公共のIDictionary <オブジェクト、オブジェクト]> [プロパティ] {取得します。}新しい辞書= <オブジェクト、オブジェクト>(); 公共IHostBuilder ConfigureHostConfiguration(アクション<IConfigurationBuilder> configureDelegate) { _configureHostConfigActions.Add(configureDelegate)。 これを返します。 } 公共IHostBuilder ConfigureAppConfiguration( アクション<HostBuilderContext、IConfigurationBuilder> configureDelegate) { _configureAppConfigActions.Add(configureDelegate)。 これを返します。 } ... }
IHostBuilderインタフェースの多くの方法は、依存性注入と関連しています。依存性注入フレームワークのセットは、主に二つの側面に反映さ:ConfigureServicesサービス登録を添加する方法を用いて、第一、第二に、UseServiceProviderFactory <TContainerBuilder>方法はIServiceProviderFactory <TContainerBuilder>植物、及びConfigureContainerの使用<TContainerBuilder>パーティ登録両者の使用ContainerBuilder工場は、さらに設定を作成します。
第三に、登録依存サービス
システムのセットアップと構成については、ConfigureServicesはアクション<HostBuilderContext、IServiceCollection>デリゲートオブジェクトが一時的に表現configureServicesActionsに対応するフィールドの同じセットに格納され、それらが最終的にビルドプロセスで使用される依存サービスを登録して処理します。
パブリッククラスHostBuilder:IHostBuilder { プライベートリスト<アクション<HostBuilderContext、IServiceCollection >> _configureServicesActions =新しいリスト<アクション<HostBuilderContext、IServiceCollection >>(); 公共IHostBuilder ConfigureServices(アクション<HostBuilderContext、IServiceCollection> configureDelegate) { _configureServicesActions.Add(configureDelegate)。 これを返します。 } ... }
直接法に加えて、ConfigureServices IHostBuilderサービス・インターフェースが登録されている呼び出して、我々はまた、いくつかの特別なサービスのためにこれらの拡張機能の登録を完了するには、次のメソッドを呼び出すことができます。二ConfigureLogging拡張メソッドのオーバーロードは、私たちはフレームワークに関連するサービスをログに記録するために登録を助ける、2つのUseConsoleLifetimeの拡張メソッドは、サービス登録のためのConsoleLifetimeを追加するためにオーバーロードされ、2つのRunConsoleAsyncさらに上の登録ConsoleLifetimeサービスのベース拡張メソッドのオーバーロード建設およびホストとしてIHostオブジェクトを起動します。
パブリック静的クラスHostingHostBuilderExtensions { パブリック静的IHostBuilder ConfigureLogging(このIHostBuilder hostBuilder、アクション<HostBuilderContext、ILoggingBuilder> configureLogging) => hostBuilder.ConfigureServices((文脈、コレクション)=> collection.AddLogging(ビルダー=> configureLogging(コンテキスト、ビルダー))) ; パブリック静的IHostBuilder ConfigureLogging(このIHostBuilder hostBuilder、アクション<ILoggingBuilder> configureLogging) => hostBuilder.ConfigureServices((文脈、コレクション)=> collection.AddLogging(ビルダー=> configureLogging(ビルダー))); パブリック静的IHostBuilder UseConsoleLifetime(このIHostBuilder hostBuilder) => hostBuilder.ConfigureServices((文脈、コレクション)=> collection.AddSingleton <IHostLifetime、ConsoleLifetime>()); パブリック静的IHostBuilder UseConsoleLifetime(このIHostBuilder hostBuilder、アクション<ConsoleLifetimeOptions> configureOptions) => hostBuilder.ConfigureServices((文脈、コレクション)=> { collection.AddSingleton <IHostLifetime、ConsoleLifetime>(); collection.Configure(configureOptions); }); パブリック静的タスクRunConsoleAsync(このIHostBuilder hostBuilder、CancellationToken cancellationToken =デフォルト) => hostBuilder.UseConsoleLifetime()ビルド()RunAsync(cancellationToken)。。。 パブリック静的タスクRunConsoleAsync(このIHostBuilder hostBuilder、アクション<ConsoleLifetimeOptions> configureOptions、CancellationToken cancellationToken =デフォルト) => hostBuilder.UseConsoleLifetime(configureOptions).Build()RunAsync(cancellationToken)。 }
第四に、登録IServiceProviderFactory <TContainerBuilder>
IServiceProviderは、コンテナが常に登録されているIServiceProviderFactory <TContainerBuilder>工場の依存関係が作成するオブジェクト。以来UseServiceProviderFactory <TContainerBuilder> IServiceFactoryAdapterこの適合を、以下のようにHostBuilderインターフェイスタイプに変換するように登録方法IServiceProviderFactory <TContainerBuilder>、汎用オブジェクトです。以下のコードセグメントに示すように、それだけでのみコンバートContainerBuilderオブジェクトタイプです。ServiceFactoryAdapter <TContainerBuilder> IServiceFactoryAdapterタイプは、達成するために、デフォルトのインタフェースです。
内部クラスServiceFactoryAdapter <TContainerBuilder>:IServiceFactoryAdapter { プライベートIServiceProviderFactory <TContainerBuilder> _serviceProviderFactory。 プライベート読み取り専用のFunc <HostBuilderContext> _contextResolver。 民間のFunc <HostBuilderContext、IServiceProviderFactory <TContainerBuilder >> _factoryResolver。 公共ServiceFactoryAdapter(IServiceProviderFactory <TContainerBuilder> serviceProviderFactory) => _serviceProviderFactory = serviceProviderFactory。 公共ServiceFactoryAdapter(機能<HostBuilderContext> contextResolver、のFunc <HostBuilderContext、IServiceProviderFactory <TContainerBuilder >> factoryResolver) { _contextResolver = contextResolver。 _factoryResolver = factoryResolver。 } パブリックオブジェクトCreateBuilder(IServiceCollectionサービス) => _serviceProviderFactory ?? _factoryResolver(_contextResolver())CreateBuilder(サービス)。 公共IServiceProvider CreateServiceProvider(オブジェクトcontainerBuilder) => _serviceProviderFactory.CreateServiceProvider((TContainerBuilder)containerBuilder)。 }
2 UseServiceProviderFactory <TContainerBuilder>オーバーロードされ、以下に示す定義のFunc IServiceProviderFactory <TContainerBuilder>オブジェクト及び第二の方法を提供するオーバーロード<HostBuilderContext、IServiceProviderFactory <TContainerBuilder >>過負荷を提供する第一の方法は、変換されServiceFactoryAdapter <TContainerBuilder>オブジェクトと_serviceProviderFactoryフィールドによって一時的に格納さに。UseServiceProviderFactory <TContainerBuilder>メソッドが呼び出されていない場合、_serviceProviderFactory戻りフィールドは、オブジェクトDefaultServiceProviderFactory ServiceFactoryAdapter <IServiceCollection>オブジェクトコードに従って作成され、また、以下に示すスニペットこれを反映しています。
パブリッククラスHostBuilder:IHostBuilder { プライベートリスト<IConfigureContainerAdapter> _configureContainerActions =新しいリスト<IConfigureContainerAdapter>(); プライベートIServiceFactoryAdapter _serviceProviderFactory =新しいServiceFactoryAdapter <IServiceCollection>(新DefaultServiceProviderFactory()); 公共IHostBuilder UseServiceProviderFactory <TContainerBuilder>(IServiceProviderFactory <TContainerBuilder>工場) { _serviceProviderFactory =新しいServiceFactoryAdapter <TContainerBuilder>(工場)。 これを返します。 } 公共IHostBuilder UseServiceProviderFactory <TContainerBuilder>(機能<HostBuilderContext、IServiceProviderFactory <TContainerBuilder >> _serviceProviderFactory =新しいServiceFactoryAdapter <TContainerBuilder>(()=> _hostBuilderContext、工場))。 これを返します。 } }
TContainerBuilderオブジェクト登録IServiceProviderFactory <TContainerBuilder>工場はさらにConfigureContainer <TContainerBuilder>方法によって提供することができる、アクション<HostBuilderContext、TContainerBuilder>オブジェクトを提供し、特定のを設定することによって行われます。この汎用デリゲートオブジェクトは、この適応はオブジェクトの本質はTContainerBuilderオブジェクトタイプに変換され、それは最終的には、以下のIConfigureContainerAdapterインターフェイスタイプに変換され、一時的に保存するために、同様の適応を行う必要があります。ConfigureContainerAdapter <TContainerBuilder>入力し、以下に示すこのインタフェースのデフォルトの実装です。
内部インタフェースIServiceFactoryAdapter { オブジェクトCreateBuilder(IServiceCollectionサービス)。 IServiceProvider CreateServiceProvider(オブジェクトcontainerBuilder)。 } 内部インタフェースIConfigureContainerAdapter { ボイドConfigureContainer(HostBuilderContext hostContext、オブジェクトcontainerBuilder)。 } 内部クラスConfigureContainerAdapter <TContainerBuilder>:IConfigureContainerAdapter { プライベートアクション<HostBuilderContext、TContainerBuilder> _action。 公共ConfigureContainerAdapter(アクション<HostBuilderContext、TContainerBuilder>アクション) => _action =アクション。 公共ボイドConfigureContainer(HostBuilderContext hostContext、オブジェクトcontainerBuilder) => _action(hostContext、(TContainerBuilder)containerBuilder)。 }
ConfigureContainer <TContainerBuilder>メソッドを次のように定義され、我々は方法がConfigureContainerAdapter <TContainerBuilder>オブジェクトにアクション<HostBuilderContext、TContainerBuilder>選択したオブジェクトを提供し、configureContainerActionsフィールドによって表されるコレクションに追加されますことを見つけます。
パブリッククラスHostBuilder:IHostBuilder { プライベートリスト<IConfigureContainerAdapter> _configureContainerActions =新しいリスト<IConfigureContainerAdapter>(); 公共IHostBuilder ConfigureContainer <TContainerBuilder>(アクション<HostBuilderContext、TContainerBuilder> configureDelegate) { _configureContainerActions.Add(新しいConfigureContainerAdapter <TContainerBuilder>(configureDelegate))。 これを返します。 } ... }
第五に、サードパーティ製の依存性注入フレームワークとの統合
私たちは、「ある依存性注入フレームワークのミニバージョンでは」猫の依存性注入フレームワークと呼ばれる簡易版を作成するための、および「適応のためのサードパーティ製の依存性注入フレームワーク、それは<TContainerBuilder>達成のためIServiceProviderFactoryを作成します」特定のタイプCatServiceProviderは、その後、我々はあなたがこのCatServiceProviderを登録することにより、猫の注入フレームワークと統合するために第三者に依存する方法を示しています。あなたは猫のフレームワークを使用している場合は、我々はサービス登録情報を定義する方法上のサービスの種類のMapToAttribute特性をマークすることができます。デモ・プログラムでは、我々は3つのサービス(フー、バーやバズ)の定義と対応するインターフェース(IFoo、IBARとIBaz)を使用するように作成されました。
パブリックインターフェースIFoo {} パブリックインターフェイスIBAR {} パブリックインターフェイスIBaz {} [MapTo(typeof演算(IFoo)、Lifetime.Root)] publicクラスはFoo:IFoo {} [MapTo(typeof演算(IBAR)、Lifetime.Root)] publicクラスバー:IBAR {} [MapTo(typeof演算(IBaz)、Lifetime.Root)] publicクラスバズ:IBaz {}
下図のようFakeHostedServiceがホストされている私たちのデモアプリケーションを提供しています。私たちは、コンストラクタで上記で定義された3つのサービスを注入し、コンストラクタは、これらの3つのサービスが正常に注入されることを保証するために、デバッグアサーションを提供します。
公共のシールクラスFakeHostedService:IHostedService { 公共FakeHostedService(IFoo fooという、IBARバー、IBazバズ) { Debug.Assertの(FOO = nullを!)。 Debug.Assertの(バー= nullを!)。 Debug.Assertの(バズ= nullを!)。 } パブリックタスクStartAsync(CancellationToken cancellationToken)=> Task.CompletedTask。 パブリックタスクStopAsync(CancellationToken cancellationToken)=> Task.CompletedTask。 }
以下に示すプログラムを担持するサービスでは、我々はConfigureServicesメソッドを呼び出すことによって負担するHostBuilderオブジェクトおよび登録FakeHostedServiceサービスを作成します。私たちの次の呼び出しCatServiceProviderのUseServiceProviderFactory方法は、登録を完了した後、登録方法CatBuilderは、アセンブリの入り口のためのサービス登録のバルクを完成呼び出します。私たちは、ホストとしてターゲットホストの建設のHostBuilderビルドメソッドを呼び出して、それを起動すると、FakeHostedServiceは、サービスが自動的に作成され、開始されますホストされています。(ソースコードここでダウンロード)
クラスプログラム { 静的な無効メイン() { 新しいHostBuilder() .ConfigureServices(SVCの=> svcs.AddHostedService <FakeHostedService>()) .UseServiceProviderFactory(新しいCatServiceProviderFactory()).ConfigureContainer <CatBuilder>(ビルダー=> builder.Register(組立.GetEntryAssembly())) .Build() .RUN(); } }
システムベアラサービス[1]:長時間実行サービスベアラ[パート]は
システムベアラサービス[2]:ベアラサービス時間を実行し、[次へ]
システムベアラサービス[3]:一般的な設計[パート]
システムベアラサービス[4]:一般的な設計〔パートII〕
系ベアラサービス[5]:ベアラサービスの起動プロセス[パート]
系ベアラサービス[6]:ベアラサービスの起動プロセス〔パートII〕