Dora.Interception,为.NET Core度身打造的AOP框架 [3]:多样化拦截器应用方式

 在《以约定的方式定义拦截器》中,我们通过对拦截器的介绍了Dora.Interception的两种拦截机制,即针对接口的“实例拦截”针对虚方法的“类型拦截”。我们介绍了拦截器的本质以及基于约定的拦截器定义方式,接下来我们将着重关注拦截器的应用问题。

一、拦截器应用解决什么问题

和有些AOP框架不同,Dora.Interception在设计刻意地将拦截器和拦截器应用刻意地分开。不仅如此,在拦截器和拦截器应用之间,我们还分离出“拦截器管道的构建”:

  • 拦截器:旨在完成单一拦截功能的实现;
  • 拦截器管道的构建:将多个拦截器按照指定的顺序构建一个管道;
  • 拦截器的应用:将构建的拦截器管道应用到被拦截的某个方法上。

二、IInterceptorChainBuilder

拦截器管道的构建由IInterceptorChainBuilder来完成,它类似于ASP.NET Core的IApplicationBuilder接口,后者利用注册的中间件来构建一个中间件管道,而IInterceptorChainBuilder则采用类似的方式将注册的拦截器构建成一个拦截器管道。如下面的代码片段所示,我们利用Use方法将表示拦截器的InterceptorDelegate 的委托对象提供给IInterceptorChainBuilder,该方法的order参数表示提供的拦截器最终在拦截器链条上的位置。拦截器管道的构建最终由Build方法来完成,构建的管道也体现为一个InterceptorDelegate类型的委托。

public interface IInterceptorChainBuilder {     InterceptorDelegate Build();     IInterceptorChainBuilder New();     IInterceptorChainBuilder Use(InterceptorDelegate interceptor, int order);      IServiceProvider ServiceProvider { get; } }

由于Dora.Interception是为.NET Core度身定制的,而.NET Core总是离不开通过通过IServiceProvider表示的DI容器,所以我们将IServiceProvider整合到IInterceptorChainBuilder中,我们在构建拦截器管道过程中所需的任何一个依赖服务都可以利用它来提取。IInterceptorChainBuilder的New方法用来创建一个新的IInterceptorChainBuilder对象,当我们开始构建一个管道的时候需要调用此方法。

虽然Dora.Interception最终总是利用InterceptorDelegate对象来表示拦截器,但是我们推荐应用程序采用我们约定的方式将拦截器定义成一个POCO类型,所谓我们为IInterceptorChainBuilder定义了如下几个扩展方法来注册一次方式定义的拦截器类型。如果调用第一个和第三个Use方法提供拦截器类型(第二个Use方法直接提供的是拦截器对象),我们最终需要利用作为DI容器的IServiceProvider对象来创建对应的实例。如果构造函数中所有的参数都是预选注册的服务,我们无需提供任何的参数,否则就需要利用arguments来提供它们。

public static class InterceptorChainBuilderExtensions {         public static IInterceptorChainBuilder Use<TInterceptor>(this IInterceptorChainBuilder builder, int order, params object[] arguments);     public static IInterceptorChainBuilder Use(this IInterceptorChainBuilder builder, object interceptor, int order);     public static IInterceptorChainBuilder Use(this IInterceptorChainBuilder builder, Type interceptorType, int order, params object[] arguments); }

三、IInterceptorProvider

IInterceptorChainBuilder仅仅是一个用来构建拦截器管道的工具而已,最终向它提供原材料(拦截器)的是一个IInterceptorProvider对象。一般来说一个拦截器类型对应一个IInterceptorProvider实现(也可可以是多个)。如下面的代码片段所示,IInterceptorProvider同样定义了一个Use方法,该方法将上面这个IInterceptorChainBuilder作为参数。在具体的实现中,我们一般会调用IInterceptorChainBuilder的Use方法来注册对应的拦截器类型。IInterceptorProvider还具有一个AllowMultiple属性表示当前类型的多个拦截器实例能够同时存在于管道中。

public interface IInterceptorProvider {     void Use(IInterceptorChainBuilder builder);     bool AllowMultiple { get; } }

IInterceptorProvider接口实际上体现了拦截器的注册方法,因为所谓的拦截器注册本质上体现为如何向IInterceptorChainBuilder提供拦截器的问题。由于标准Attribute是我们推荐的注册方式,我们为它们定义了如下这个名为InterceptorAttribute的基类。InterceptorAttribute可以标注到类型、属性和方法上,它的AllowMultiple属性与标注到该Attribute上的AttributeUsageAttribute的AllowMultiple属性一致,默认值为False。

[AttributeUsage((AttributeTargets) (AttributeTargets.Property | AttributeTargets.Method | AttributeTargets.Class), AllowMultiple=false)] 
                        
关键字:
50000+
5万行代码练就真实本领
17年
创办于2008年老牌培训机构
1000+
合作企业
98%
就业率

联系我们

电话咨询

0532-85025005

扫码添加微信