依賴注入的入門階段

自從被打槍不會ASP.NET Core 後,就不斷的學習新的NetCore技術,先後買了幾本書,

第一本:完全精通微軟Web架構: ASP.Net Core 3最新強實戰

說實在的,這本書似乎不太適合我看,首先對於兩岸的文字描述,對我來講實在有點障礙,在專有名詞上,我還是偏好非中國那邊的用語,另外這本的講解,讓我覺得文字說明不夠簡單扼要,常常看了一個段落,然後實在看不明白到底要表達什麼,看過另外一本的依賴注入後才發覺這本書文字的累贅,不過其實還是不錯的書,至少把NetCore的最根本原理與NetCore如何實現跨平台與各個Middleware說明的很徹底,還是值得的一本,只不過我要看很久。

第二本:依賴注入:原理、實作與設計模式 (Dependency Injection: Principles, Practices, Patterns, 2/e)

這本在看了上面第一本ASP.NET Core 3 後,發現依賴注入是ASP.NET Core 核心概念,並且第一本的依賴注入講解的內容我覺得實在不懂,後來又買了這本。 著實的認為這本真的是非常好的書,

依賴注入的概念假想

說道依賴注入,書上用插座的範例來說明設計模式的譬喻,來讓讀者能夠深刻體會設計模式是如何實現的。不免俗的我自己也有自己一套譬喻假想,常常人家說到依賴注入就會說到 IoC (控制反轉),然後就是依賴注入的 組合根,建構子注入,屬性注入,方法注入,DI容器,光是這麼多名詞,硬記也不知道在記什麼,但是讀到後面卻產生一個很相似的譬喻:{『武林的世界』

首先,要成為一個武林高手,必須內外兼修,內就是修煉內功心法,外就是修煉武學招式, 對於依賴注入,IoC控制反轉就感覺是修煉內功心法,為何如此說法呢?先看看名詞定義,以下引用完全精通微軟Web架構: ASP.Net Core 3最新強實戰

控制反轉(Inverse of Control)

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

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

什麼是『組合根』

可以組合應用程式中使用的類別。 將需要實體物件的建立作業,全部集中化到一個地方,而這個負責處理作業的區塊就是『組合根』,通常是應用程式的啟動點,在NetCore就是Main方法中。

建構子注入

必須在Public 修飾子的建構子中以建構子參數的形式,定義這份依賴需求,要求外部提供物件。 重要:建構子參數要增加必須在同一個建構子增加額外的參數,避免使用多載方式導致混淆。

屬性注入

接著讓我們來看看屬性注入,顧名思義就是從公開的屬性丟進去,因此有時候也會被叫做設值注入。 通常我們會在 「外部使用者要能夠隨時切換依賴對象」或是「類別已經有預設值了,但希望提供使用者可以覆寫掉預設值的彈性」時用到屬性注入

方法注入

當依賴對象可能會隨著每次呼叫的方法不同,又或者是依賴對象不變但每次的使用方都有可能變化時,就需要透過方法參數的形式來設定依賴關係。

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


DI容器技術

所謂的DI容器技術指的就是一套軟體函式庫,協助我們將許多包括『物件關聯組合』,『管理物件生命週期』等作業自動化。

由上述的定義可瞭解到,使用依賴注入,會有許多相關的知識需要理解,在此不多講解,可參考 依賴注入:原理、實作與設計模式 (Dependency Injection: Principles, Practices, Patterns, 2/e)
 第七章到第九章的內容

然而DI容器其實是協助我們管理跟自動化,而提供許多的函式方法來協助我們,下面就會記錄與說明函式的方法。讓我們加入華山派的劍宗吧。

依賴注入的容器:Autofac的記錄

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](圖解系列與常用套件)

官方文檔

Comments

comments powered by Disqus

Published

Category

後端程式

Tags

Contact