依賴注入的心得筆記

學習依賴注入的起點

因為被指出不熟 ASP.NET Core,我開始補 .NET Core 的相關知識,前後買了幾本書。

第一本:

天瓏網路書店 | 完全精通微軟 Web 架構:ASP.Net Core 3 最新強實戰 (有些許瑕疵,不影響閱讀)
掌握 ASP.NET Core 3 的全新開發平台,學習跨平台開發、依賴植入及中介軟體的實用技巧,適合所有 .NET 開發者 | 書名:完全精通微軟 Web 架構:ASP.Net Core 3 最新強實戰 (有些許瑕疵,不影響閱讀),ISBN:9865501406,作者:蔣金楠,出版社:深智數位,出版日期:2020-07-21,分類:.NET、ASP.NET

說實在的,第一本不太適合我。兩岸用語不同,專有名詞讀起來有些障礙;有些段落也不夠簡潔,我常要反覆讀才明白。看完另一本依賴注入的書後,這種感受更明顯。不過它對 .NET Core 的基本原理、跨平台實作和 Middleware 解釋得很完整,仍有參考價值,只是我需要花較多時間消化。

第二本:

天瓏網路書店 | 依賴注入:原理、實作與設計模式 (Dependency Injection: Principles, Practices, Patterns, 2/e)
探索依賴注入的原理與實作,提升程式碼彈性與可測試性,適合.NET開發者與軟體設計師的必讀指南 | 書名:依賴注入:原理、實作與設計模式 (Dependency Injection: Principles, Practices, Patterns, 2/e),ISBN:9864344986,作者:Steven van Deursen, Mark Seemann 著,出版社:博碩文化,出版日期:2020-07-30,分類:Design Pattern

讀完第一本 ASP.NET Core 3 後,我知道依賴注入是 ASP.NET Core 的核心概念,但當時仍沒看懂相關說明,所以又買了第二本。
第二本讀起來清楚許多,我很推薦。

我怎麼理解依賴注入

書中用插座比喻依賴注入。我也試著用「武林世界」來理解 IoC(控制反轉)、組合根、建構子注入、屬性注入、方法注入和 DI 容器。這些名詞單獨硬記很抽象,放進同一個比喻後反而容易掌握。

武林高手要內外兼修:內功心法決定根基,武學招式則是實際做法。
在這個比喻裡,IoC 控制反轉像內功心法。先看原書的名詞定義:完全精通微軟Web架構: ASP.Net Core 3最新強實戰

控制反轉(Inverse of Control)

對於任何一項工作,不論大小,基本上都可以分解成對應的步驟,所以任何一項工作的實施都有固定的流程,而IoC的控制就是視作『針對流程的控制』。一般來講,設計模式是為了解決一個實際問題的方案,但是IoC沒有一個針對性的問題領域,本身也沒有提供一種可操作的解決方案,所以認為視為IoC是一種『設計原則

由以上的定義可以瞭解,控制反轉是一個概念,一個設計原則,當我們在定義介面的時候,對於功能的切割是由哪些類別來注入,實際的控制權是由外部注入的,所以『針對流程的控制』要如何定義的靈活與彈性就要靠日後的練習,完全就是一個心法的概念。

什麼是『組合根』

組合根用來組合應用程式中的類別。
建立實體物件的工作集中在同一處,這個位置就是「組合根」。它通常位於應用程式的啟動點;在 .NET Core 中就是 Main 方法。

建構子注入

在 public 建構子中,以參數宣告所需的依賴,並由外部提供物件。
如果要增加依賴,應在同一個建構子加入參數,避免用多載造成混淆。

屬性注入

屬性注入就是透過公開屬性提供依賴,所以也稱為設值注入。
通常我們會在 「外部使用者要能夠隨時切換依賴對象」或是「類別已經有預設值了,但希望提供使用者可以覆寫掉預設值的彈性」時用到屬性注入

方法注入

當依賴對象會隨每次方法呼叫而不同,或依賴本身不變但使用方會變化時,可以透過方法參數設定依賴關係。

上述這些定義就是依賴注入的方法,組合根就是在定義如何引用各個類別,組合起所有的類別,這些方式就是類似拳腳基本功,有了基本的拳腳功夫,接下來就是討論到DI容器,DI容器可以說是各個門派的獨有的技能。

DI容器技術

DI 容器是一套軟體函式庫,用來自動處理物件關聯組合與物件生命週期。

依賴注入還有不少細節,這裡不展開,可參考
依賴注入:原理、實作與設計模式 (Dependency Injection: Principles, Practices, Patterns, 2/e)
第七章到第九章的內容

DI 容器主要協助管理與自動化,並提供各種註冊方法。以下記錄這些方法;繼續沿用前面的武林比喻,就當作加入華山派劍宗。

Autofac DI 容器筆記

Autofac .NET Inversion of Control Container

public void ConfigureContainer(ContainerBuilder builder)
{
	Assembly domainAssembly = typeof(ITimeProvider).Assembly;

	builder.RegisterType<DefaultTimeProvider>().As<ITimeProvider>().SingleInstance();
	builder.RegisterInstance<IUserContext>(new AspNetUserContextAdapter());
	builder.Register(c => new CommerceContext(this.Configuration.ConnectionString))
		.InstancePerLifetimeScope();

	builder.RegisterAssemblyTypes(domainAssembly).AsClosedTypesOf(typeof(ICommandService<>));

	builder.RegisterGenericDecorator(
		typeof(AuditingCommandServiceDecorator<>), typeof(ICommandService<>));

	builder.RegisterGenericDecorator(
		typeof(SaveChangesCommandServiceDecorator<>), typeof(ICommandService<>));
	builder.RegisterGenericDecorator(
		typeof(SecureCommandServiceDecorator<>), typeof(ICommandService<>));

	// ---- Start code section 13.4.4 ----
	builder.RegisterAssemblyTypes(domainAssembly)
		.As(type =>
			from interfaceType in type.GetInterfaces()
			where interfaceType.IsClosedTypeOf(typeof(IEventHandler<>))
			select new KeyedService("handler", interfaceType));

	builder.RegisterGeneric(typeof(CompositeEventHandler<>))
		.As(typeof(IEventHandler<>))
		.WithParameter(
			(p, c) => true,
			(p, c) => c.ResolveNamed("handler", p.ParameterType));
	// ---- End code section 13.4.4 ----

	// Register adapters to external systems
	builder.RegisterAssemblyTypes(typeof(WcfBillingSystem).Assembly)
		.AsImplementedInterfaces();

	// Register repositories
	builder.RegisterAssemblyTypes(typeof(SqlProductRepository).Assembly)
		.Where(type => type.Name.EndsWith("Repository"))
		.AsImplementedInterfaces();
}

TODO:持續學習中。
RegisterType
RegisterInstance
RegisterAssemblyTypes
RegisterGenericDecorator

參考資料:

[Dot Net Core](圖解系列與常用套件) :: 2022 iThome 鐵人賽
1.透過圖解了解軌跡,哪個部位要做什麼事,後續會有什麼後果,都是在地圖上推演預測的。圖解就像地圖般且有順序的走向來說明。 2.少有任何架構框架會比微軟寫得…
Welcome to Autofac’s documentation! — Autofac 7.0.0 documentation
Author image
關於 Richard Zheng
About me 喜歡爬山,瑜伽,溜冰,喜歡新奇的事,最喜歡的還是寫程式帶來的成就感,對於資訊會不斷的出現新事物也能抱持好奇與熱忱。近期開始將學習的心得寫在Blog,發現思路更清晰也加深了記憶。 紙上得來終覺淺,絕知此事要躬行