前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >AOP框架Dora.Interception 3.0 [3]: 拦截器设计

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

作者头像
蒋金楠
发布2019-10-24 10:24:23
3070
发布2019-10-24 10:24:23
举报
文章被收录于专栏:大内老A大内老A

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

一、InvocationContext

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

代码语言:javascript
复制
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类型。

代码语言:javascript
复制
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类型。

代码语言:javascript
复制
public delegate InterceptDelegate InterceptorDelegate(InterceptDelegate next);

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

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

代码语言:javascript
复制
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方法中。

代码语言:javascript
复制
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]: 自定义拦截器注册方式

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019-10-23 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、InvocationContext
  • 二、两个委托对象
  • 三、基于约定的拦截器定义
  • 四、两种注入方式
相关产品与服务
消息队列 TDMQ
消息队列 TDMQ (Tencent Distributed Message Queue)是腾讯基于 Apache Pulsar 自研的一个云原生消息中间件系列,其中包含兼容Pulsar、RabbitMQ、RocketMQ 等协议的消息队列子产品,得益于其底层计算与存储分离的架构,TDMQ 具备良好的弹性伸缩以及故障恢复能力。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档