按照单一职责的原则,拦截器只负责需要的拦截操作的执行,至于它采用何种方式应用到目标方法上,以及它在整个拦截器管道中的位置则属于“拦截器注册”的范畴。Dora.Interception提供了几种典型的注册方法,用户也可以根据自己的需求实现自己的注册方式。

一、IInterceptorProvider

一般来说,每一个拦截器类型都对应着一个IInterceptorProvider实现类型,后者利用其Use方法负责将前者放置到拦截器管道指定的位置。如下面的代码所示,IInterceptorProvider还具有一个布尔类型的AllowMultiple属性,它表示相同类型的多一个拦截器对象是否可以同时应用到同一个方法上。如果该属性返回False,Dora.Interception只会选择其中一个。

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

IInterceptorProvider的Use方法具有一个IInterceptorChainBuilder类型的参数。IInterceptorChainBuilder类似于ASP.NET Core中的IApplicationBuilder,我们将InterceptorDelegate 对象表示的拦截器根据指定的位置(order属性)注册到IInterceptorChainBuilder对象上,并最终利用其Build方法构建一个通过InterceptorDelegate 表示的拦截器管道。

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

由于大部分情况下的拦截器都是根据约定定义的,所以我们为IInterceptorChainBuilder 定义了如下的扩展方法。

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

二、基于特性的拦截器注册方式

通过在类型和方法/属性成员上标注对应特性是最常用的拦截器注册方式,这样的特性一般继承自InterceptorAttribute。如下面的代码片段所示,InterceptorAttribute实现了IInterceptorProvider接口,它的定义了Order属性来表示注册拦截器最终在管道中的位置。AllowMultiple 属性来源于应用到当前特性类型上的AttributeUsageAttribute特性的同名属性。

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Property, AllowMultiple = false)]
public abstract class InterceptorAttribute : Attribute, IInterceptorProvider
{
public int Order { get; set; }
public bool AllowMultiple {get;}
public abstract void Use(IInterceptorChainBuilder builder);
}

对于在《拦截器的设计》中定义了那个FoobarInterceptor,我们可以将对应的特性定义成如下的形式。

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Property, AllowMultiple = false)]
public class FoobarAttribute: InterceptorAttribute
{
private readonly string _baz;
public FoobarAttribute (string baz) => _baz = baz;
public override void Use(IInterceptorChainBuilder builder)=> builder.Use<FoobarInterceptor>(Order, _baz);
}

三、拦截器和特性合二为一

如果嫌将拦截器和对应的特性分开定义太繁琐,我们可以将它们合二为一。对于在《拦截器的设计》中定义了那个FoobarInterceptor可以定义成如下的形式。

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Property, AllowMultiple = false)]
public class FoobarAttribute:InterceptorAttribute
{
private readonly string _baz;
public FoobarAttribute(string baz)=>_baz = baz; public async InvokeAsync(InvocationContext context, IFoo foo, IBar bar)
{
await PreInvokeAsync();
await context.ProceedAsync();
await PostInvokeAsync();
} public override void Use(IInterceptorChainBuilder builder) => builder.Use(this, Order, _baz);
}

四、NonInterceptableAttribute

如果某个类型或者方法不应该被拦截,我们可以在上面标注一个NonIntercetableAttribute。以如下这个Foobarbaz类型为例,由于FoobarInterceptorAttribute标注在类型,意味着对应的拦截器会应用到所有可被拦截的虚方法上。如果Baz方法不应该被拦截,应该在上面标注NonIntercetableAttribute特性。

[FoobarInterceptor]
public class Foobarbaz
{
public virtual Foo();
public virtual Bar();
[NonInterceptable]
public virtual Baz();
}

除了利用NonIntercetableAttribute屏蔽所有的拦截器之外,我们还可以利用它屏蔽指定类型的拦截器。如下面的代码片段所示,Foobarbaz类型上标注了三个InterceptorAttribute,但是方法Baz只需要BazInterceptorAttribute,我们可以利用NonIntercetableAttribute特性将其他两个屏蔽掉。

[FooInterceptor]
[BarInterceptor]
[BazInterceptor]
public class Foobarbaz
{
public virtual Foo();
public virtual Bar();
[NonInterceptable(typeof(FooInterceptorAttribute), typeof(BarInterceptorAttribute), )]
public virtual Baz();
}

AOP框架Dora.Interception 3.0 [1]: 编程体验
AOP框架Dora.Interception 3.0 [2]: 实现原理
AOP框架Dora.Interception 3.0 [3]: 拦截器设计
AOP框架Dora.Interception 3.0 [4]: 基于特性的拦截器注册
AOP框架Dora.Interception 3.0 [5]: 基于策略的拦截器注册
AOP框架Dora.Interception 3.0 [6]: 自定义拦截器注册方式

AOP框架Dora.Interception 3.0 [4]: 基于特性的拦截器注册的更多相关文章

  1. AOP框架Dora.Interception 3.0 [5]: 基于策略的拦截器注册方式

    注册拦截器旨在解决如何将拦截器应用到目标方法的问题.在我看来,针对拦截器的注册应该是明确而精准的,也就是我们提供的注册方式应该让拦截器准确地应用到期望的目标方法上,不能多也不能少.如果注册的方式过于模 ...

  2. AOP框架Dora.Interception 3.0 [1]: 编程体验

    .NET Core正式发布之后,我为.NET Core度身定制的AOP框架Dora.Interception也升级到3.0.这个版本除了升级底层类库(.NET Standard 2.1)之外,我还对它 ...

  3. AOP框架Dora.Interception 3.0 [2]: 实现原理

    和所有的AOP框架一样,我们必须将正常的方法调用进行拦截,才能将应用到当前方法上的所有拦截器纳入当前调用链.Dora.Interception采用IL Eimit的方式实现对方法调用的拦截,接下来我们 ...

  4. AOP框架Dora.Interception 3.0 [3]: 拦截器设计

    对于所有的AOP框架来说,多个拦截器最终会应用到某个方法上.这些拦截器按照指定的顺序构成一个管道,管道的另一端就是针对目标方法的调用.从设计角度来将,拦截器和中间件本质是一样的,那么我们可以按照类似的 ...

  5. 全新升级的AOP框架Dora.Interception[1]: 编程体验

    多年之前利用IL Emit写了一个名为Dora.Interception(github地址,觉得不错不妨给一颗星)的AOP框架.前几天利用Roslyn的Source Generator对自己为公司写的 ...

  6. 全新升级的AOP框架Dora.Interception[2]: 基于&ldquo;约定&rdquo;的拦截器定义方式

    Dora.Interception有别于其他AOP框架的最大的一个特点就是采用针对"约定"的拦截器定义方式.如果我们为拦截器定义了一个接口或者基类,那么拦截方法将失去任意注册依赖服 ...

  7. 全新升级的AOP框架Dora.Interception[3]: 基于特性标注的拦截器注册方式

    在Dora.Interception(github地址,觉得不错不妨给一颗星)中按照约定方式定义的拦截器可以采用多种方式注册到目标方法上.本篇文章介绍最常用的基于"特性标注"的拦截 ...

  8. 全新升级的AOP框架Dora.Interception[4]: 基于Lambda表达式的拦截器注册方式

    如果拦截器应用的目标类型是由自己定义的,Dora.Interception(github地址,觉得不错不妨给一颗星)可以在其类型或成员上标注InterceptorAttribute特性来应用对应的拦截 ...

  9. 全新升级的AOP框架Dora.Interception[6]: 框架设计和实现原理

    本系列前面的五篇文章主要介绍Dora.Interception(github地址,觉得不错不妨给一颗星)的编程模式以及对它的扩展定制,现在我们来聊聊它的设计和实现原理.(拙著<ASP.NET C ...

随机推荐

  1. 分享一个撩妹、装13神技能,0基础用Python暴力破解WiFi密码

    WiFi密码Python暴力破解   Python密码破解部分截图 获取视频资料,转发此文+点击喜欢,然后获取资料请加Python交流群:580478401,就可以获取视频教程+源码 环境准备: py ...

  2. Sql server中用现有表中的数据创建Sql的Insert插入语句

    之前,在Codeproject发表过一篇关于用现有表中数据创建Insert的Sql语句的存储过程,今天将其搬到这里来,注意本存储过程仅适用于SQL SERVER. 介绍 一些时候,你想导出一些现有表中 ...

  3. 在vue中选中某个标签,并且对其属性进行操作

    第一步:在标签中添加ref="111"属性 第二步:this.$refs.111.属性=""   此步骤是一111为标记选中了要操作的标签,通过点属性的方法,进 ...

  4. Centos Linux下使用Metasploit渗透android

    .newline{display:block}.katex .base{position:relative;white-space:nowrap;width:min-content}.katex .b ...

  5. PAT甲级专题|树的遍历

    PAT甲级专题-树的遍历 涉及知识点:树.建树.深度优先搜索.广度优先搜索.递归 甲级PTA 1004 输出每一层的结点,邻接表vector建树后.用dfs.bfs都可以边搜边存当前层的数据, #in ...

  6. DRF Django REST framework APIView(一)

    什么是REST? REST是一个标准,一种规范,遵循REST风格可以使开发的接口通用,便于调用者理解接口的作用. 使url更容易理解,让增删改清晰易懂,在前后端分离开发中按照这一规范能加快开发效率,减 ...

  7. 【玩转MLS系列】基础教程

    1.申请华为机器学习服务MLS标准版服务: 1.如果还未注册华为云,请先进入华为云官网https://www.huaweicloud.com/进行注册:如果已注册,请登录,转第2步. 2.在华为云官网 ...

  8. 基于webpack实现多html页面开发框架三 图片等文件路径替换、并输出到打包目录

    一.解决什么问题      1.图片路径替换.并输出到打包目录      2.输出目录清理 二.需要安装的包 file-loader:html.css中图片路径替换,图片输出到打包目录:命令:npm ...

  9. 《手把手教你》系列进阶篇之1-python+ selenium自动化测试 - python基础扫盲(详细教程)

    1. 简介 如果你从一开始就跟着宏哥看博客文章到这里,基础篇和练习篇的文章.如果你认真看过,并且手动去敲过每一篇的脚本代码,那边恭喜你,至少说你算真正会利用Python+Selenium编写自动化脚本 ...

  10. [TimLinux] JavaScript 中循环执行和定时执行

    1. 两对函数 // 循环执行 // 在每个毫秒数之后,调用函数 var timeid = window.setInterval(函数名, 毫秒数); window.clearInterval(tim ...