WebAPI中有设计了几种管道(Channel),大概如下:HttpMessageHandler,ActionFilter管道,ExceptionFilter管道。在三种管道中HttpMessageHandler管道与ExceptionFilter管道是基于级别设计的,ActionFilter管道是基于方法级别设计的。对于ActionFilter管道,因为采用的是AOP的思想,所以按方法级别去设计。
在看WebAPI源码过程中对ActionFilter管道中何用的表达示树与闭包等内容之前并没有下手写过,所以想仿写一个简单版的ActionFilter来练练手。
在写demo的过程中,我将Action的返回值固定为ResponseMessage,在ActionFilter实现过程中并没有遵循WebAPI的具体规则,只是实现ActionFilter对Action执行前后的切入与多ActionFilter的注入。
IActionFilter
public interface IActionFilter { Task<ResponseMessage> ExecuteActionFilterAsync(ActionContext actionContext, CancellationToken cancellationToken, Func<Task<ResponseMessage>> continuation); }
IActionFilter我是直接Copy源码里面的。IActionFilter接口,只定义了一个ExecuteActionFilterAsync方法。对于方法前两个参数好理解,至于最后一个类型为Func<Task<ResponseMessage>>的参数continuation,它是组成ActionFilter的关键。在WebAPI中将所有Action以及IActionFilter的ExecuteActionFilterAsync方法通过闭包的方式封装成Func<Task<ResponseMessage>>,再将每个Func<Task<ResponseMessage>逐级向ActionFilter中添加,以此来完成整个ActionFilter管道的构建。
Action到Func<Task<ResponseMessage>>
对于Action,因为我已经将返回值默认为ResponseMessage,所以我并没有对返回值做转换处理。因为Func<Task<ResponseMessage>>是一个无参的委托,所以在向Func<Task<ResponseMessage>>的转换分成两步:
- 定义类ActionInvoker(在demo中本身这个类并不是必须的,定义这个类主要是为是练习表达示树)
- 再针对ActionInvoker生成Func<Task<ResponseMessage>>
Func<Task<ResponseMessage>> result = () => { return invoker.Invoke(context, cancellationToken); };
通过闭包生成ActionFilter管道
之前已经提到将IActionFilter的ExecuteActionFilterAsync方法转换成Func<Task<ResponseMessage>>,并逐级添加到ActionFilter管道中,这个时候就必须要用到闭包了。
ActionInvoker invoker = new ActionInvoker(context.Action); Func<Task<ResponseMessage>> result = () => { return invoker.Invoke(context, cancellationToken); }; for (int i = 0; i <= filters.Count - 1; i++) { IActionFilter filter = filters[i]; Func<Func<Task<ResponseMessage>>, IActionFilter, Func<Task<ResponseMessage>>> chainContinuation = (continuation, innerFilter) => { return () => { return innerFilter.ExecuteActionFilterAsync(context, cancellationToken, continuation); }; }; result = chainContinuation(result, filter); }
对于这个仿写的ActionFilter相对来说比较简单,所以以后有时候的话看能不能把Exception管道加进来,同时按照WebAPI的ActionFilter管道的规则去处理。
源码
Github: https://github.com/BarlowDu/WebAPI (FilterChannelDemo)