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

Autofac 套件之如何快速擴充客製註冊方法 - 以變更RegisterDecorator為例

logoAutofac

上一篇討論了 Autofac套件內部是如何運作的,稍微了解整個流程,雖然不是百分百都將所有細節都展現出來,但也可以了解近七、八成的主要執行方式。

這篇是要幫助,利用這個套件後,欲加上自己的註冊方式,或者遇到沒有支援的情境時要擴充一個註冊函示,要如何下手。

其實觀察套件供註冊的方式,與其它貢獻者貢獻出來的新的註冊函示,都是利用了C#的 Extension Method 的特性。這篇也僅僅是利用了此一特性,做了一個擴充的簡單範例。如果熟悉上一篇的內容,可以設計出獨特的註冊情境,利用它的 Container  ComponentRegistry 、 RegistrationBuilder、 ComponentRegistration 等內容來操作。

而此篇只是利用改寫的方式,做一個開頭與釋例,將原本難以理解的 RegisterDecorator 做一個改寫,使之更簡便易讀操作。進而了解體驗如何做擴充。


首先來看套件提供的 RegisterDecorator 如何使用。裝飾者模式是我們很常運用的一套模式,是一種擴充物件的好方法。

想像一下要處理:

  new DecoratorSuperSessionInjectionClass( new DecoratorSessionInjectionClass( new DecoratorInjectionClass(...) ) ) 

DecoratorInjectionClass 被 DecoratorSessionInjectionClass 裝飾,然後 DecoratorSessionInjectionClass 又被DecoratorSuperSessionInjectionClass裝飾。

一層又一層的裝飾,是不是有點複雜與易寫錯,如少一個括號等,某種程度上不太好讀與花費時間在偵錯。

如果可以DI注入的方式解決,是非常棒的。

於是Autofac提供了一個註冊方式(RegisterDecorator) 解決了此問題。

//Decorator Injection 註冊
builder.RegisterType().Named("Decorate");

builder.RegisterDecorator(
  (c, inner) => new DecoratorSessionInjectionClass(inner), fromKey: "Decorate"
).Named("DecoratorSession");

builder.RegisterDecorator(
  (c, inner) => new DecoratorSuperSessionInjectionClass(inner), fromKey: "DecoratorSession"
).Named("DecoratorSuperSession");



//Decorator Resolve 產生實例

var decoreteHandler = AutofacContainer.builder.ResolveNamed("DecoratorSuperSession");

 


如此可以實現使用類別 DecoratorSuperSessionInjectionClass 產生的實例,且確實包裝了對應的類別。

但是這種註冊方式有點難理解,每裝飾一層要寫一次.....令人有點頭痛。

於是,我們可以客製改寫一個較清楚的註冊,來達成一樣的作用,且程式碼某種程度較好理解。

將新增一個擴充函式 :

public static class ContainerBuilderExtensions
{
   
    public static  List< Autofac.Builder.IRegistrationBuilder<TService, LightweightAdapterActivatorData, Autofac.Builder.DynamicRegistrationStyle> >
             RegisterDecoratorChain<TService>(
                 this ContainerBuilder builder,
                 List<DecoratorSeal<TService>> Decorators )
        {
            if (builder == null) throw new ArgumentNullException(nameof(builder));
            if (Decorators == null) throw new ArgumentNullException(nameof(Decorators));

            List<Autofac.Builder.IRegistrationBuilder<TService, LightweightAdapterActivatorData, Autofac.Builder.DynamicRegistrationStyle>> lisBuilder =
                 new List<Autofac.Builder.IRegistrationBuilder<TService, LightweightAdapterActivatorData, Autofac.Builder.DynamicRegistrationStyle>>();

            foreach (var decorator in Decorators)
            {
                lisBuilder.Add(
                    builder.RegisterDecorator<TService>(
                       decorator.DecoratorDelegateFunc, fromKey: decorator.fromWhichService
                    ).Named<TService>(decorator.FinalDecoratorServiceName)
                );
            }

            return lisBuilder;
        }


} 

傳入一個 List<DecoratorSeal<>>的裝飾目標集合,可以用泛型帶入要註冊的類別。而這個 DecoratorSeal 類別為裝飾目標的資訊,定義如下:

public class DecoratorSeal<TService>
{

    public string fromWhichService;  //要裝飾哪個服務

    public Func<Autofac.IComponentContext, TService, TService> DecoratorDelegateFunc; // 委派裝飾執行的函示

    public string DecoratorServiceName; //裝飾後的服務名稱
} 

於是我們可以註冊此一擴充的裝飾者: 


builder.RegisterType<DecoratorInjectionClass>().Named<IDecoratorClass>("Decorate");  //先定義好原始基本的類別對應的服務

List<DecoratorSeal<IDecoratorClass>> lisDecorators = new List<Autofac_EX.DecoratorSeal<IDecoratorClass>>();
lisDecorators.Add(
       new DecoratorSeal<IDecoratorClass>()
       {
           DecoratorDelegateFunc = (c, inner) => new DecoratorSessionInjectionClass(inner),
           fromWhichService = "Decorate",
           DecoratorServiceName = "DecoratorSession"
       }
    ); //DecoratorSessionInjectionClass 裝飾了 DecoratorInjectionClass
lisDecorators.Add(
       new DecoratorSeal<IDecoratorClass>()
       {
           DecoratorDelegateFunc = (c, inner) => new DecoratorSuperSessionInjectionClass(inner),
           fromWhichService = "DecoratorSession",
           DecoratorServiceName = "DecoratorSuperSession"
       }
    ); //DecoratorSuperSessionInjectionClass 裝飾了 DecoratorSessionInjectionClass

builder.RegisterDecoratorChain(lisDecorators); 

執行好註冊後,於程式主體就可以resolve出實體:


var decoreteHandler = (DecoratorSuperSessionInjectionClass)AutofacContainer.builder.ResolveNamed<IDecoratorClass>("DecoratorSuperSession"); 

改成較易讀的方式,也只是改變傳入的方式,但利用VS的開發工具更快的原因是僅僅餵入參數該給的值,就達成註冊的效果。

這篇的目的為: 利用簡單的改寫現有的註冊函式來說明如何擴充autofac套件的註冊方式。

如果有任何新的情境產生新的註冊擴充,會再分享出來幫助各位。

Autofac 內部運作如何幫助 .NET MVC Controller 做到 DI - 概述運作圖...
Autofac 套件內部如何達成 IOC 目的 - 概述圖解
 

評論

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

Captcha 圖像