iT邦幫忙

2022 iThome 鐵人賽

DAY 3
1
自我挑戰組

[Dot Net Core](圖解系列與常用套件)系列 第 3

[Dot Net Core](圖解系列) 3. IOC - 牽動框架設計的重要環節 - An important part of system design-an IOC overview

  • 分享至 

  • xImage
  •  

https://ithelp.ithome.com.tw/upload/images/20220903/20144614LZ4DEWQj0T.jpg

Dot Net Core 有非常多處會使用到DI的機制,即使是Host要建置起來的途中,也會常常使用。而外部的相關套件,也常常會利用此一機制來設計;無論是套件或自己開發,IOC會成為整個設計中的重要環節考量。

會將Host準備DI機制的過程做一個概述。首先看到ServiceProviderFactory:
https://ithelp.ithome.com.tw/upload/images/20220903/20144614kC4heSBMP6.jpg

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

https://ithelp.ithome.com.tw/upload/images/20220903/20144614EOnZ89YN5c.jpg

接下來是前面 "Host 運作總覽" 中有提到的CreateServiceProvider部分。HostBuilder 在執行 Build 此一動作中,第5個步驟 CreateServiceProvider ,處理 _configureServiceActions中的委派事件集合,其中一個是將Startup類別實體新增,然後跑它的ConfigureServices方法。這個方法提供開法者有機會指定相關的IOC準備,儲存這些DI設定到 ServiceCollection 中。

之後在把註冊好的DI設定,利用 HostBuilder._serviceProviderFactory將包含ServiceCollection 資訊的 Provider 新增起來,並指派到 HostBuilder._appServices。

https://ithelp.ithome.com.tw/upload/images/20220903/20144614PkKI0N3Wlh.jpg

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

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

https://ithelp.ithome.com.tw/upload/images/20220903/20144614R9WWWJwcMP.jpg

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與組件資訊等。

https://ithelp.ithome.com.tw/upload/images/20220903/20144614oA9zOxwcmC.jpg

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

DynamicServiceProviderEngine 成功取得對應的 CallSite後,最後再利用RuntimeResolver 來產生對應的實體。

https://ithelp.ithome.com.tw/upload/images/20220903/20144614rV91YyJL4V.jpg

上圖再展式 ServiceProvider 與 DynamicServiceProviderEngine 關聯中,有一個繼承的類別為 CompiledServiceProviderEngine,這邊算是額外細項,指出ServiceProviderEngine 實際上跑 RuntimeResolver 是透過 ILEmitResolverBuilder 來作的。

未來會展示實際上 .Net Core 的 MVC Controller 類別是怎麼進行 DI 的,這邊先稍微示意:
https://ithelp.ithome.com.tw/upload/images/20220903/20144614fhxGQNC982.jpg

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

https://ithelp.ithome.com.tw/upload/images/20220903/20144614fCZCWJ4tCr.jpg

接著就跑 ServiceProviderEngineScope的 GetService,如前面幾張圖的說明即產生實體。
Dot Net Core 要實行 DI ,其實是有一些複雜的過程,但於此節先行大致上的了解,後續說明其它流程時,有提到DI (GetService) 即可來此參考,不必再進行累述!

文亦收錄於:
https://czxdas.medium.com/dot-net-core-2-ioc-an-important-part-of-system-design-an-overview-of-preparations-549a74301c8d


上一篇
[Dot Net Core](圖解系列) 2. Host 運作總覽 - Host Outline diagram of Framework operation
下一篇
[Dot Net Core](圖解系列) 4. 實際如何實行DI Resolve Service
系列文
[Dot Net Core](圖解系列與常用套件)30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言