Dora.Interception[6]框架设计原理是什么?

摘要:本系列前面的五篇文章主要介绍Dora.Interception(github地址,觉得不错不妨给一颗星)的编程模式以及对它的扩展定制,现在我们来聊聊它的设计和实现原理。(拙著《ASP.NET Core 6框架揭秘》6折优惠,首印送签名专属书
本系列前面的五篇文章主要介绍Dora.Interception(github地址,觉得不错不妨给一颗星)的编程模式以及对它的扩展定制,现在我们来聊聊它的设计和实现原理。(拙著《ASP.NET Core 6框架揭秘》6折优惠,首印送签名专属书签)。 目录 一、调用链抽象 二、基于约定的拦截器定义 三、基于调用上下文的依赖注入容器 四、拦截器的提供 五、调用链的构建 六、方法拦截的实现原理 七、依赖注入框架的整合 八、看看生成的代理类 一、调用链抽象从设计模式来看,Dora.Interception采用了“职责链”模式。我们将应用到同一个方法的多个拦截器以及针对目标方法的调用构建成如下所示的“调用链”。调用链在执行过程中共享同一个“调用上下文”,后者提供当前调用的上下文信息,比如目标对象、调用方法、输出参数和返回值等。每个拦截器不仅可以利用这些上下文信息执行对应的操作,还可以直接利用此上下文修改参数和返回值,并且自行决定是否继续执行后续调用。 我们定义了如下这个抽象类InvocationContext来表示上述的调用上下文。对于参数/返回值的提取,我们设计成抽象方法以避免因装箱/拆箱带来的性能问题。拦截器针对其他服务的依赖是一个基本的需求,所以我们为InvocationContext定义了一个InvocationServices属性来提供针对当前调用的IServiceProvider对象。在默认情况下,我们会为每次调用创建一个服务范围,并利用此范围的IServiceProvider对象作为这个InvocationServices属性的值。但是对于ASP.NET Core应用,我们会直接使用针对当前请求的IServiceProvider对象。 public abstract class InvocationContext { public object Target { get; } = default!; public abstract MethodInfo MethodInfo { get; } public abstract IServiceProvider InvocationServices { get; } public IDictionary<object, object> Properties { get; } public abstract TArgument GetArgument<TArgument>(string name); public abstract TArgument GetArgument<TArgument>(int index); public abstract InvocationContext SetArgument<TArgument>(string name, TArgument value); public abstract InvocationContext SetArgument<TArgument>(int index, TArgument value); public abstract TReturnValue GetReturnValue<TReturnValue>(); public abstract InvocationContext SetReturnValue<TReturnValue>(TReturnValue value); protected InvocationContext(object target); internal InvokeDelegate Next { get; set; } = default!; public ValueTask ProceedAsync() => Next.Invoke(this); } 既然有了这样一个能够体现当前方法调用上下文的InvocationContext类型,那么上述的“调用量”就可以表示成如下这个InvokeDelegate委托。熟悉ASP.NET Core的读者可以看出Dora.Interception的调用链设计与ASP.NET Core框架的“中间件管道”几乎一致,InvocationContext和InvokeDelegate分别对应后者的HttpContext和RequestDelegate。
阅读全文