上一篇討論了 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套件的註冊方式。
如果有任何新的情境產生新的註冊擴充,會再分享出來幫助各位。