Dora.Interception,为.NET Core度身打造的AOP框架:全新的版本
Dora.Interception 1.0(可以訪問GitHub地址:https://github.com/jiangjinnan/Dora)推出有一段時(shí)間了,最近花了點(diǎn)時(shí)間將它升級(jí)到2.0,主要有如下的改進(jìn):
提供了原生的動(dòng)態(tài)代理生成底層框架Dora.DynamicProxy:之前依賴第三方框架Castle實(shí)現(xiàn)最底層的代理生成,但是它不支持基于Task的并行編程(也就是說通過它編寫的Interceptor無法實(shí)現(xiàn)異步執(zhí)行),所以我采用IL Emit的方式自行實(shí)現(xiàn)了這部分的功能,這些底層的功能實(shí)現(xiàn)在Dora.DynamicProxy中。
提供了如下兩種形式的攔截方案:
基于實(shí)例封裝:如果消費(fèi)的類型是一個(gè)接口,那么提供的類型為動(dòng)態(tài)生成的代理類,該代理類封裝了目標(biāo)對(duì)象。對(duì)于每一個(gè)動(dòng)態(tài)生成的接口實(shí)現(xiàn)成員來說,它會(huì)負(fù)責(zé)執(zhí)行應(yīng)用的Interceptor。如果需要調(diào)用目標(biāo)方法,被封裝的目標(biāo)對(duì)象的對(duì)應(yīng)方法會(huì)被調(diào)用。這種攔截方案要求目標(biāo)類型實(shí)現(xiàn)一個(gè)接口,接口中定義的所有方法和屬性都是可以被攔截的。
基于類型繼承:如果目標(biāo)類型是一個(gè)非Sealed類型,一個(gè)繼承與它的代理類型會(huì)被動(dòng)態(tài)生成。如果Interceptor被應(yīng)用到目標(biāo)類型的某個(gè)虛方法或者屬性上,該成員會(huì)在生成的代理類中被重寫,進(jìn)而使Interceptor得以執(zhí)行。這種攔截機(jī)制適合非Sealed類型,只有虛方法/屬性能夠被攔截。
提供了針對(duì)屬性的攔截支持:之前的版本支持針對(duì)方法的攔截,最新版本中提供了針對(duì)屬性的攔截支持。我們可以選擇將Interceptor應(yīng)用到某個(gè)類型的屬性上,也可以單獨(dú)應(yīng)用到該屬性的Get或者Set方法上。
一、對(duì)基于Task的并行編程的支持
由于Dora.Interception將Dora.DynamicProxy作為默認(rèn)的動(dòng)態(tài)代理類型生成框架,所以不在依賴任何第三發(fā)框架,因此在編程會(huì)變得更加簡(jiǎn)單,現(xiàn)在我們來做一個(gè)簡(jiǎn)單的演示。在安裝了最新版本的NuGet包Dora.Interception之后,我們可以按照 “約定” 的方式來定義如下這么一個(gè)簡(jiǎn)單的Interceptor類型。為了驗(yàn)證針對(duì)Task并行編程的支持,我們特意在攔截方法InvokeAsync中Delay了一秒鐘。
public class FoobarInterceptor { ? ?private InterceptDelegate _next; ?
?public FoobarInterceptor(InterceptDelegate next){_next = next;} ?
?public async Task InvokeAsync(InvocationContext context){Console.WriteLine("Interception task starts."); ? ? ?
?await Task.Delay(1000);Console.WriteLine("Interception task completes."); ?
? ? ?await _next(context);} }
我將Interceptor和Interceptor的注冊(cè)特意區(qū)分開來,Interceptor的注冊(cè)默認(rèn)采用特性標(biāo)注的形式來實(shí)現(xiàn),為此我們?yōu)樯厦娑x的FoobarInterceptor創(chuàng)建一個(gè)對(duì)應(yīng)的特性類型FoobarAttribute。如下面的代碼片段所示,FoobarAttribute派生于InterceptorAttribute,FoobarInterceptor在重寫的Use方法中被構(gòu)建,在構(gòu)建過程中可以指定該Interceptor在整個(gè)Interceptor Chain的位置(Order)。
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Property)] public class FoobarAttribute : InterceptorAttribute { ? ?public override void Use(IInterceptorChainBuilder builder){builder.Use<FoobarInterceptor>(this.Order);} }
接下來我們定義了簡(jiǎn)單的類型Demo來使用FoobarInterceptor,Demo實(shí)現(xiàn)了接口IDemo,FoobarAttribute標(biāo)注在需要被攔截的方法InvokeAsync上。
public interface IDemo {Task InvokeAsync(); }public class Demo : IDemo {[Foobar] ? ?
public Task InvokeAsync(){Console.WriteLine("Target method is invoked."); ? ? ?
?return Task.CompletedTask;} }
由于Dora.Interception實(shí)現(xiàn)了與.NET Core的Dependency Injection的無縫集成,所以我們只需要采用我們熟悉的方式來提供服務(wù)實(shí)例就可以了。如下面的代碼片段所示,我們將IDemo和Demo之間的映射關(guān)系注冊(cè)到創(chuàng)建的ServiceCollection上之后,并沒有調(diào)用BuildeServiceProvider方法,而是調(diào)用BuildInterceptableServiceProvider來創(chuàng)建提供服務(wù)的ServiceProvider。
class Program {static void Main(string[] args){ ? ? ? ?var demo = new ServiceCollection().AddSingleton<IDemo, Demo>() .BuildeInterceptableServiceProvider().GetRequiredService<IDemo>(); ?demo.InvokeAsync();Console.WriteLine("Continue...");Console.Read();} }
如下所示的是這段代碼的執(zhí)行結(jié)果,我們可以看到應(yīng)用的FoobarInterceptor被正常執(zhí)行,而且它完全是以異步的方式執(zhí)行的。
二、基于虛方法的攔截
如果Demo沒有實(shí)現(xiàn)任何的接口,并且它不是一個(gè)Sealed類型,它的虛方法和屬性也是可以被攔截的。比如我們將Demo做了如下的改動(dòng)。
public class Demo {[Foobar] ??public virtual Task InvokeAsync(){Console.WriteLine("Target method is invoked."); ? ?
? ?return Task.CompletedTask;} }
所有Demo沒有了接口實(shí)現(xiàn),所以我們需要對(duì)服務(wù)注冊(cè)代碼做相應(yīng)的修改。執(zhí)行修后的代碼,我們依然會(huì)得到相同的輸出。
class Program { ? ?static void Main(string[] args){ ? ? ? ?var demo = new ServiceCollection().AddSingleton<Demo, Demo>() .BuildeInterceptableServiceProvider().GetRequiredService<Demo>(); ?demo.InvokeAsync();Console.WriteLine("Continue...");Console.Read();} }三、屬性也可被攔截
對(duì)于上一版本來說,被攔截的成員僅限于普通的方法,最新的版本增加對(duì)屬性的支持。如果一個(gè)Interceptor被直接應(yīng)用到某個(gè)屬性上,它實(shí)際上會(huì)被同時(shí)應(yīng)用到該屬性的Get和Set方法上。比如我們?cè)贒emo類型上添加一個(gè)Value屬性,并在上面標(biāo)準(zhǔn)FoobarAttribute。
public class Demo {[Foobar] ? ?public virtual object Value { get; set; } }接下來我們按照如下的方式獲取一個(gè)Demo對(duì)象,并調(diào)用其Value屬性的Set和Get方法。
class Program { ??static void Main(string[] args){ ? ? ? ?var demo = new ServiceCollection().AddSingleton<Demo, Demo>().BuildInterceptableServiceProvider().GetRequiredService<Demo>();Console.WriteLine("Set...");demo.Value = new object();Console.WriteLine("Get..."); ? ? ?
?var value = demo.Value;Console.Read();} }
從如下的輸出結(jié)果可以看出,我們注冊(cè)到Value屬性上的FoobarInterceptor在Get和Set方法被調(diào)用的時(shí)候都執(zhí)行了一遍。
如果我們只需要在某個(gè)屬性的Get或者Set方法上應(yīng)用某個(gè)Interceptor,我們也可以作針對(duì)性的標(biāo)注。在如下的代碼片段中,我們將FoobarAttrbute標(biāo)準(zhǔn)到Get方法上。
public class Demo { ??public virtual object Value { [Foobar] get; set; } }
再次執(zhí)行程序,我們會(huì)發(fā)現(xiàn)FoobarInterceptor僅僅在調(diào)用Value屬性的Get方法時(shí)被執(zhí)行了一次。
原文地址:https://www.cnblogs.com/artech/p/dora2-01.html
.NET社區(qū)新聞,深度好文,歡迎訪問公眾號(hào)文章匯總 http://www.csharpkit.com
總結(jié)
以上是生活随笔為你收集整理的Dora.Interception,为.NET Core度身打造的AOP框架:全新的版本的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 小白带你入坑xamarin系列之环境搭建
- 下一篇: C# 这些年来受欢迎的特性