Dora.Interception[2]如何定义基于约定的拦截器?
摘要:Dora.Interception(github地址,觉得不错不妨给一颗星)有别于其他AOP框架的最大的一个特点就是采用针对“约定”的拦截器定义方式。如果我们为拦截器定义了一个接口或者基类,那么拦截方法将失去任意注册依赖服务的灵活性。除此之
Dora.Interception(github地址,觉得不错不妨给一颗星)有别于其他AOP框架的最大的一个特点就是采用针对“约定”的拦截器定义方式。如果我们为拦截器定义了一个接口或者基类,那么拦截方法将失去任意注册依赖服务的灵活性。除此之外,由于我们采用了动态代码生成的机制,我们可以针对每一个目标方法生成对应的方法调用上下文,所以定义在拦截上下文上针对参数和返回值的提取和设置都是泛型方法,这样可以避免无谓的装箱和拆箱操作,进而将引入拦截带来的性能影响降到最低。(拙著《ASP.NET Core 6框架揭秘》6折优惠,首印送签名专属书签)
目录
一、方法调用上下文
二、拦截器类型约定
三、提取调用上下文信息
四、修改输出参数和返回值
五、控制拦截器的执行顺序
六、短路返回
七、构造函数注入
八、方法注入
九、ASP.NET Core应用的适配
一、方法调用上下文针对同一个方法调用的所有拦截器都是在同一个方法调用上下文中进行的,我们将这个上下文定义成如下这个InvocationContext基类。我们可以利用Target和MethodInfo属性得到当前方法调用的目标对象和目标方法。泛型的GetArgument和SetArgument用于返回和修改传入的参数,针对返回值的提取和设置则通过GetReturnValue和SetReturnValue方法来完成。如果需要利用此上下文传递数据,可以将其置于Properties属性返回的字典中。InvocationServices属性返回针对当前方法调用范围的IServiceProvider。如果在ASP.NET Core应用中,这个属性将返回针对当前请求的IServiceProvider,否则Dora.Interception会为每次方法调用创建一个服务范围,并返回该范围内的IServiceProvider对象。
public abstract class InvocationContext
{
public object Target { get; }
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);
public ValueTask ProceedAsync() => Next.Invoke(this);
}和ASP.NET Core的中间件管道类似,应用到同一个方法上的所有拦截器最终也会根据指定的顺序构建成管道。对于某个具体的拦截器来说,是否需要指定后续管道的操作是由它自己决定的。我们知道ASP.NET Core的中间件最终体现为一个Func<RequestDelegate,RequestDelegate>委托,作为输入的RequestDelegate委托代表后续的中间件管道,当前中间件利用它实现针对后续管道的调用。
