選單
GSS 技術部落格
在這個園地裡我們將從技術、專案管理、客戶對談面和大家分享我們多年的經驗,希望大家不管是喜歡或是有意見,都可以回饋給我們,讓我們有機會和大家對話並一起成長!
若有任何問題請來信:gss_crm@gss.com.tw
3 分鐘閱讀時間 (528 個字)

[Dot Net Core](Graphic series)2.IOC An important part of system design-an overview of preparations

netcorelogo

 Dot Net Core 有非常多處會使用到DI的機制,即使是Host要建置起來的途中,也會常常使用。而外部的相關套件,也常常會利用此一機制來設計;無論是套件或自己開發,IOC會成為整個設計中的重要環節考量。 以下會將Host準備DI機制的過程做一個概述。首先看到ServiceProviderFactory:

最初會於Program.Main中,呼叫靜態類別 Host 的 CreateHostBuilder 方法,新增HostBuilder實體,接著呼叫擴充方法UseDefaultServiceProvider,新增了ServiceFactoryAdapter實體,並將實體內的_contextResolver 與 _factoryResolver 作委派設定。最後將HostBuilder 的_serviceProviderFactory參考到 ServiceFactoryAdapter 實體。

接下來是前面 "運作概述圖解" 中有提到的CreateServiceProvider部分。HostBuilder 在執行 Build 此一動作中,第5個步驟 CreateServiceProvider ,處理 _configureServiceActions中的委派事件集合,其中一個是將Startup類別實體新增,然後跑它的ConfigureServices方法。這個方法提供開法者有機會指定相關的IOC準備,儲存這些DI設定到 ServiceCollection 中。 之後在把註冊好的DI設定,利用 HostBuilder._serviceProviderFactory將包含ServiceCollection 資訊的 Provider 新增起來,並指派到 HostBuilder._appServices。

剛剛有提到,Host 的_serviceProviderFactory參考到 ServiceFactoryAdapter 實體,所以呼叫_serviceProviderFactory.CreateBuilder 其實就是呼叫ServiceFactoryAdapter.CreateBuilder。此主要是說明,ServiceFactoryAdapter會利用委派好的_contextResolver 與 _factoryResolver 產生 DefaultServiceProviderFactory 實體。

以下會再詳細追蹤 ServiceFactoryAdapter 如何轉換 DefaultServiceProviderFactory ,進一步將註冊好的 ServiceCollection 資料建置到 ServiceProviderEngine中,成為最後 .NET Core IOC 的 DI 引擎。

ServiceCollection 使用擴充方法,將服務註冊到 ServiceDescriptor 類別型態 的集合中。ServiceDescriptor 存放註冊相關資訊如 什麼類別型態、要如何產生實體、是什麼生命週期種類等等。也就是說,依照 AddSingleton、AddScoped、AddTransient、Add 等Method來決定其 ImplementationType、ImplementationInstance、ImplementationFactory要怎麼給值或要不要給值。ServiceCollection 還有另一個擴充方法,BuildServiceProvider,會產生DynamicServiceProviderEngin,繼承了 ServiceProvider,此 Provider 包含了一個極為重要的引擎,為ServiceProviderEngine。引擎會利用 CallSiteFactory 去找對應的 callSite,影響後續DI要產生對應的實體時所執行的內容。

Provider 最後會指派到 HostBuilder的 _appServices,可以提供 GetService 將要實行 DI 的 Type 傳入後,即可透過其剛剛準備的資訊作產生實體。

GetService決定要執行什麼方式產生實體,是在服務註冊的時候,註冊到 ServiceDescriptor 就先收集好的,都在system.type中的資訊內,
最後在 GetService 中 取得 ServiceCallSite 時 經過這些資訊判斷,產生 對應種類的 callSite (ConstantCallSite、FactoryCallSite、ConstructorCallSite)
Type.GetTypeInfo() 可以看見相關資訊包含有沒有constructor、有哪些method、public或private與組件資訊等。

上圖展示ServiceProvider 與 DynamicServiceProviderEngine 關聯圖。ServiceProvider._engine 即為 DynamicServiceProviderEngine , 而 DynamicServiceProviderEngine 包含了 CallSiteFactory , 此物件會儲存註冊好的服務所需要的 CallSite ,如果曾經產生過會暫存在 _callSiteCache集合裡。CallSiteFactory 要如何產生對應的 CallSite,勢必會利用 ServiceCollection 裡註冊好的資訊。 DynamicServiceProviderEngine 成功取得對應的 CallSite後,最後再利用RuntimeResolver 來產生對應的實體。

上圖再展式 ServiceProvider 與 DynamicServiceProviderEngine 關聯中,有一個繼承的類別為 CompiledServiceProviderEngine,這邊算是額外細項,指出ServiceProviderEngine 實際上跑 RuntimeResolver 是透過 ILEmitResolverBuilder 來作的。 未來會展示實際上 .Net Core 的 MVC Controller 類別是怎麼進行 DI 的,這邊先稍微示意:

要產生 MVC Controller 類別實體,主要透過 ControllerActionInvoker 與 ControllerContext 的資訊, 經過 ControllerFactoryProvider 呼叫 CreateControllerFactory 方法。

接著就跑 ServiceProviderEngineScope的 GetService,如前面幾張圖的說明即產生實體。

Dot Net Core 要實行 DI ,其實是有一些複雜的過程,但於此節先行大致上的了解,後續說明其它流程時,有提到DI (GetService) 即可來此參考,不必再進行累述!

[Dot Net Core](Graphic series )3.How to actually i...
[Dot NET Core] (Graphic series )1. Host Outline di...
 

評論

尚無評論
已經注冊了? 這裡登入
Guest
2024/05/03, 週五

Captcha 圖像