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

一、InvocationContext

我们为整个拦截器管道定义了一个统一的执行上下文,并将其命名为InvocationContext。如下面的代码片段所示,我们可以利用InvocationContext对象得到方法调用上下文的相关信息,其中包括两个方法(定义在接口和实现类型),目标对象、参数列表(含输入和输出参数)、返回值(可读写)。Properties 属性提供了一个自定义的属性容器,我们可以利用它来存放任意与当前方法调用上下文相关的信息。如果需要调用后续的拦截器或者目标方法(如果当前为最后一个拦截器),我们只需要直接调用ProceedAsync方法即可。

public abstract class InvocationContext
{
public abstract MethodInfo Method { get; }
public MethodInfo TargetMethod { get; }
public abstract object Target { get; }
public abstract object[] Arguments { get; }
public abstract object ReturnValue { get; set; }
public abstract IDictionary<string, object> Properties { get; }
public Task ProceedAsync();
}

二、两个委托对象

既然所有的拦截器都是在同一个InvocationContext上下文中执行的,那么我们可以将任意的拦截操作定义成一个Func<InvocationContext, Task>对象。Func<InvocationContext, Task>对象不仅可以表示某项单一的拦截操作,实际上包括目标方法调用在内的整个拦截器管道都可以表示成一个Func<InvocationContext, Task>对象。由于这个委托的重要性,我们将它定义成如下这个InterceptDelegate类型。

public delegate Task InterceptDelegate(InvocationContext context);

如果以ASP.NET Core框架的请求处理管道作为类比,那么InvocationContext相当于HttpContext,而InterceptDelegate自然对应的就是RequestDelegate。我们知道ASP.NET Core框架将中间件表示成Func<RequestDelegate, RequestDelegate>对象,那么拦截器自然就可以表示成一个Func<InterceptDelegate, InterceptDelegate>。如果读者朋友对此不太理解,可以参阅我的文章《200行代码,7个对象——让你了解ASP.NET Core框架的本质》。由于拦截器的重要性,我们也将它定义成如下这个单独的InterceptorDelegate类型。

public delegate InterceptDelegate InterceptorDelegate(InterceptDelegate next);

三、基于约定的拦截器定义

Dora.Interception和ASP.NET Core采用几乎一致的设计。对于ASP.NET Core来说,虽然中间件最终是通过Func<InterceptDelegate, InterceptDelegate>表示的,但是我们可以将中间件定义成一个按照约定定义的类型。Dora.Interception同样支持基于约定的拦截器类型定义。

public class FoobarInterceptor
{
private readonly IFoo _foo;
private readonly IBar _bar;
private readonly string _baz; public FoobarInterceptor(IFoo foo, IBar bar, string baz)
{
_foo = foo;
_bar = bar;
_baz = baz;
} public async InvokeAsync(InvocationContext context)
{
await PreInvokeAsync();
await context.ProceedAsync();
await PostInvokeAsync();
}
}

如上定义的FoobarInterceptor展现了一个典型的基于约定定义的拦截器类型,它体现了如下的约定:

  • 拦截器类型是一个实例类型(不能定义成静态类型);
  • 必须具有一个公共构造函数,其中可以定义任意参数。
  • 拦截操作定义在一个名为InvokeAsync的方法中,该方法的返回类型为Task,其中包含一个InvocationContext类型的参数。如果需要调用后续拦截器管道,需要显式调用InvocationContext上下文的ProceedAsync方法。

四、两种注入方式

由于拦截器最终是利用.NET Core的依赖注入框架提供的,所以依赖服务可以直接注入拦截器的构造函数中。但是就服务的生命周期来讲,拦截器本质上是一个Singleton服务,我们不应该将Scoped服务注入到它的构造函数中。如果具有针对Scoped服务注入的需要,我们应该将它注入到InvokeAsync方法中。

public class FoobarInterceptor
{
private readonly string _baz; public FoobarInterceptor(string baz)
{
_baz = baz;
} public async InvokeAsync(InvocationContext context, IFoo foo, IBar bar)
{
await PreInvokeAsync();
await context.ProceedAsync();
await PostInvokeAsync();
}
}

当Dora.Interception在调用InvokeAsync方法的时候,它会利用当前Scope的IServiceProvider对象来提供其参数。对于ASP.NET Core应用来说,如果拦截器的执行在整个请求处理的调用链中,这个IServiceProvider对象就是当前HttpContext的RequestServices属性。如果当前IServiceProvider不存在,作为根的IServiceProvider对象会被使用。

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 [3]: 拦截器设计的更多相关文章

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

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

  2. AOP框架Dora.Interception 3.0 [4]: 基于特性的拦截器注册

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

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

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

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

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

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

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

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

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

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

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

  8. 全新升级的AOP框架Dora.Interception[6]: 实现任意的拦截器注册方式

    Dora.Interception提供了两种拦截器注册方式,一种是利用标注在目标类型.属性和方法上的InterceptorAttribute特性,另一种采用基于目标方法或者属性的调用表达式.通过提供的 ...

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

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

随机推荐

  1. web网站常用功能测试点总结

    目录 一.输入框 二.搜索功能 三.添加.修改功能 四.删除功能 五.注册.登录模块 六.上传图片测试 七.查询结果列表 八.返回键检查 九.回车键检查 十.刷新键检查 十一.直接URL链接检查 十二 ...

  2. day 14 内置函数

    复习了解: \t   输出一个制表符,协助在输出文本时,垂直方向保持对齐 \n       换行符 print(r"\n ")  #  在字符串前面加r 不会改变字符串的内容 a ...

  3. Java Class类常用方法描述

    一 生成Class对象的三种方式 1 Class.forName("全路径名") 2  类名.Class 3 实例对象.getClass() 接着看三种方式生成Class对象的区别 ...

  4. flask实现验证码并验证

    效果图: 点击图片.刷新页面.输入错误点击登录时都刷新验证码 实现步骤: 第一步:先定义获取验证码的接口 verificationCode.py #验证码 @api.route('/imgCode') ...

  5. mysql 基础知识整理

    什么是MySQL? MySQL 是一种关系型数据库,在Java企业级开发中非常常用,因为 MySQL 是开源免费的,并且方便扩展.阿里巴巴数据库系统也大量用到了 MySQL,因此它的稳定性是有保障的. ...

  6. postgresql密码加强-passwordcheck源码修改三种以上字符

    目录 1.使用方式 2.效果 3.源码修改 1.参考pg_cron的源码在配置文件内增加一个参数 2.修改源码配置校验数字 因数据库入网检测须修改密码级别,在源有的passwordcheck插件上进行 ...

  7. Djangoday2第二个app加减法

    第二个app 计算新建一个app在view定义显示的内容修改urls指定连接对应的视图测试另一种通过路径传参的方式访问网址路径传参的urls定义方法网址路径传参测试urls的urlnamedjango ...

  8. SDWebImage学习之 NSCache

    1.使用SDWebImage的好处 1.异步下载(避免主线程卡死) 2.做好图片缓存(这样就不需要每次都加载网络图片) 3.解决了循环利用的问题 很容易造成内存警告

  9. Python-TCP客户端程序开发

    TCP客户端,需要与服务端建立连接,连接建立成功后才可以进行数据的传输. # 1.导入模块 import socket if __name__ == '__main__': # 2.创建套接字对象 t ...

  10. 转:mysql 安装失败 start service执行不下去

    简单说一下自己安装mysql的经历坑点,新手应该都会遇到.新买了一个电脑,第一次安装的情况:在网上下载好几个不同的mysql,安装都在最后一步执行的时候,执行不下去,最后打开客户端,就是闪一下就消失了 ...