前言c#
前面一篇中讲解了过滤器执行以前的建立,经过实现IFilterProvider注册到当前的HttpConfiguration里的服务容器中,固然默认的基础服务也是有的,而且根据这些提供程序所得到的的过滤器信息集合进行排序。本篇就会对过滤器在建立完以后所作的一系列操做进行讲解。api
ASP.NETWeb API 过滤器建立、执行过程(二)浏览器
FilterGrouping过滤器分组类型服务器
FilterGrouping类型是ApiController类型中的私有类型,它的做用就如同它的命名同样,用来对过滤器集合进行分组,在上一篇中咱们看到,在通过调用HttpActionDescriptor类型的GetFilterPipeline()方法以后回去获取到排序事后的过滤器信息集合Collection<FilterInfo>。下面咱们看一下FilterGrouping类型定义:框架
示例代码1-1async
privateclassFilterGrouping { //Fields privateList<IActionFilter>_actionFilters=newList<IActionFilter>(); privateList<IAuthorizationFilter>_authorizationFilters=newList<IAuthorizationFilter>(); privateList<IExceptionFilter>_exceptionFilters=newList<IExceptionFilter>(); //Methods publicFilterGrouping(IEnumerable<FilterInfo>filters) { foreach (FilterInfoinfoinfilters) { IFilterinstance=info.Instance; Categorize<IActionFilter>(instance, this._actionFilters); Categorize<IAuthorizationFilter>(instance, this._authorizationFilters); Categorize<IExceptionFilter>(instance, this._exceptionFilters); } } privatestaticvoidCategorize<T>(IFilterfilter, List<T>list) where T : class { T item=filteras T; if (item!=null) { list.Add(item); } } //Properties publicIEnumerable<IActionFilter>ActionFilters { get { returnthis._actionFilters; } } publicIEnumerable<IAuthorizationFilter>AuthorizationFilters { get { returnthis._authorizationFilters; } } publicIEnumerable<IExceptionFilter>ExceptionFilters { get { returnthis._exceptionFilters; } } }
在代码1-1中咱们看到在FilterGrouping类型的构造函数中便会对过滤器信息集合进行分组了,固然了分组的时候是调用FilterGrouping类型中的放吧,在Categorize()方法中就是根据实例的类型来进行判断的,最后由FilterGrouping类型中的三个公共属性来表示分组事后的不一样类型的过滤器集合。ide
过滤器执行过程函数
在上个篇幅中咱们经过示例了解到过滤器管道的生成过程以及结果,咱们就来看一下执行的过程,顺带再看下过滤器管道的结果是否是如上篇上所说的那样。ui
先看服务器端(Selfhost)的代码:this
代码1-2
usingSystem.Web.Http.Controllers; usingSystem.Web.Http.Filters; usingNameSpaceControllerThree; namespaceSelfHost { classProgram { staticvoidMain(string[] args) { HttpSelfHostConfigurationselfHostConfiguration= newHttpSelfHostConfiguration("http://localhost/selfhost"); using (HttpSelfHostServerselfHostServer=newHttpSelfHostServer(selfHostConfiguration)) { selfHostServer.Configuration.Routes.MapHttpRoute( "DefaultApi", "api/{controller}/{id}", new { id=RouteParameter.Optional }); selfHostServer.Configuration.Services.Replace(typeof(IAssembliesResolver), newCustomAssembliesResolver.LoadSpecifiedAssembliesResolver()); //添加全局过滤器 selfHostServer.Configuration.Filters.Add(newWebAPIController.Filter.CustomConfigurationActionFilterAttribute()); selfHostServer.OpenAsync(); Console.WriteLine("服务器端服务监听已开启"); Console.Read(); } } } }
这里只有一个添加全局行为过滤器的这么一句代码,其他的部分就不解释了。
而后咱们接着看控制器部分,以下示例代码:
代码1-3
namespaceNameSpaceControllerThree { [CustomControllerAuthorizationFilter] [CustomControllerActionFilter] publicclassWriterAndReadController : ApiController { [CustomActionFilter] [CustomControllerActionAuthorizationFilter] publicstringGet() { StringBuilderstrBuilder=newStringBuilder(); HttpActionDescriptoractionDescriptor=this.Configuration.Services.GetActionSelector().SelectAction(this.ControllerContext); System.Collections.ObjectModel.Collection<FilterInfo>filtersInfo=actionDescriptor.GetFilterPipeline(); foreach (varfilterinfiltersInfo) { strBuilder.AppendLine("【FilterName:"+filter.Instance.GetType().Name+",FilterScope:"+filter.Scope.ToString()+"】"); } returnstrBuilder.ToString(); } } }
对于上一篇,这里的修改只是在控制器类型和控制器方法上各自新增了一个受权过滤器,下面咱们就来看一下过滤器的定义,以下示例代码:
代码1-4
/// <summary> /// 全局的行为过滤器 /// </summary> publicclassCustomConfigurationActionFilterAttribute : FilterAttribute, IActionFilter { publicTask<System.Net.Http.HttpResponseMessage>ExecuteActionFilterAsync(System.Web.Http.Controllers.HttpActionContextactionContext, System.Threading.CancellationTokencancellationToken, Func<Task<System.Net.Http.HttpResponseMessage>>continuation) { Console.WriteLine(this.GetType().Name); returncontinuation(); } } /// <summary> /// 控制器级行为过滤器 /// </summary> publicclassCustomControllerActionFilterAttribute : FilterAttribute, IActionFilter { publicTask<System.Net.Http.HttpResponseMessage>ExecuteActionFilterAsync(System.Web.Http.Controllers.HttpActionContextactionContext, System.Threading.CancellationTokencancellationToken, Func<Task<System.Net.Http.HttpResponseMessage>>continuation) { Console.WriteLine(this.GetType().Name); returncontinuation(); } } /// <summary> /// 控制器方法级行为过滤器 /// </summary> publicclassCustomActionFilterAttribute : FilterAttribute, IActionFilter { publicTask<System.Net.Http.HttpResponseMessage>ExecuteActionFilterAsync(System.Web.Http.Controllers.HttpActionContextactionContext, System.Threading.CancellationTokencancellationToken, Func<Task<System.Net.Http.HttpResponseMessage>>continuation) { Console.WriteLine(this.GetType().Name); returncontinuation(); } } /// <summary> /// 控制器级受权访问过滤器 /// </summary> publicclassCustomControllerAuthorizationFilterAttribute : FilterAttribute, IAuthorizationFilter { publicTask<System.Net.Http.HttpResponseMessage>ExecuteAuthorizationFilterAsync(System.Web.Http.Controllers.HttpActionContextactionContext, System.Threading.CancellationTokencancellationToken, Func<Task<System.Net.Http.HttpResponseMessage>>continuation) { Console.WriteLine(this.GetType().Name); returncontinuation(); } } /// <summary> /// 控制器方法级受权访问过滤器 /// </summary> publicclassCustomControllerActionAuthorizationFilterAttribute : FilterAttribute, IAuthorizationFilter { publicTask<System.Net.Http.HttpResponseMessage>ExecuteAuthorizationFilterAsync(System.Web.Http.Controllers.HttpActionContextactionContext, System.Threading.CancellationTokencancellationToken, Func<Task<System.Net.Http.HttpResponseMessage>>continuation) { Console.WriteLine(this.GetType().Name); returncontinuation(); } }
在代码1-4中,咱们能够看到代码1-3中全部使用到的过滤器类型和代码1-2中添加全局过滤器类型。
如今咱们看一下最后的结果
图1
黑色框的结果为SelfHost服务器端过滤器执行过程的输出,在代码1-4中咱们能够看到,这个得出的一个结论是受权过滤器不论是什么应用范围的都是优于行为过滤器的,而在同一种类型的过滤器中是根据应用范围来肯定执行顺序的,这个跟下面的浏览器里的内容有点关系,浏览器里显示的就是全部过滤器在排序后的管道里的样子,能够看到管道里单纯的就是按照应用范围的级别来排序的,至于这个过滤器是什么类型在处理排序的时候则是一点都不关心的。
过滤器执行过程-代码分析
首先看一下以下示意图,能够表明了在控制器执行的过程当中过滤器的执行过程。
图2
上面经过示例来讲明了过滤器的执行过程,如今咱们来看一下在框架的源码中是什么样的,由于在过滤器执行过程当中还包含了其它方面的知识点,因此这个是早晚都要看的,下面咱们就来看一下吧。
代码1-5
returnInvokeActionWithExceptionFilters(InvokeActionWithAuthorizationFilters(actionContext, cancellationToken, authorizationFilters, ()=>actionDescriptor.ActionBinding.ExecuteBindingAsync(actionContext, cancellationToken).Then<HttpResponseMessage>(delegate { this._modelState=actionContext.ModelState; returnInvokeActionWithActionFilters(actionContext, cancellationToken, actionFilters, () =>controllerServices.GetActionInvoker().InvokeActionAsync(actionContext, cancellationToken))(); }, newCancellationToken(), false))(), actionContext, cancellationToken, exceptionFilters);
在代码1-5中涉及到三个静态方法,咱们先来看一下:
InvokeActionWithExceptionFilters()
InvokeActionWithAuthorizationFilters()
InvokeActionWithActionFilters()
示例代码以下:
代码1-6
internalstaticTask<HttpResponseMessage>InvokeActionWithExceptionFilters(Task<HttpResponseMessage>actionTask, HttpActionContextactionContext, CancellationTokencancellationToken, IEnumerable<IExceptionFilter>filters) { returnactionTask.Catch<HttpResponseMessage>(delegate (CatchInfo<HttpResponseMessage>info) { HttpActionExecutedContextexecutedContext=newHttpActionExecutedContext(actionContext, info.Exception); filters=filters.Reverse<IExceptionFilter>(); IEnumerable<Task>asyncIterator=fromfilterinfiltersselectfilter.ExecuteExceptionFilterAsync(executedContext, cancellationToken); boolrunSynchronously=true; Task<HttpResponseMessage>task=TaskHelpers.Iterate(asyncIterator, cancellationToken, true).Then<HttpResponseMessage>(delegate { if (executedContext.Response!=null) { returnTaskHelpers.FromResult<HttpResponseMessage>(executedContext.Response); } returnTaskHelpers.FromError<HttpResponseMessage>(executedContext.Exception); }, newCancellationToken(), runSynchronously); returninfo.Task(task); }, newCancellationToken()); }
代码1-7
internalstaticFunc<Task<HttpResponseMessage>>InvokeActionWithAuthorizationFilters(HttpActionContextactionContext, CancellationTokencancellationToken, IEnumerable<IAuthorizationFilter>filters, Func<Task<HttpResponseMessage>>innerAction) { filters=filters.Reverse<IAuthorizationFilter>(); returnfilters.Aggregate<IAuthorizationFilter, Func<Task<HttpResponseMessage>>>(innerAction, (continuation, filter) => () =>filter.ExecuteAuthorizationFilterAsync(actionContext, cancellationToken, continuation)); }
代码1-8
internalstaticFunc<Task<HttpResponseMessage>>InvokeActionWithActionFilters(HttpActionContextactionContext, CancellationTokencancellationToken, IEnumerable<IActionFilter>filters, Func<Task<HttpResponseMessage>>innerAction) { filters=filters.Reverse<IActionFilter>(); returnfilters.Aggregate<IActionFilter, Func<Task<HttpResponseMessage>>>(innerAction, (continuation, filter) => () =>filter.ExecuteActionFilterAsync(actionContext, cancellationToken, continuation)); }
这里咱们先看代码1-5表示了过滤器执行的全部过程,忽然的看起来这1-5代码的可读性过低了,多是跟我水平的关系,我看起来非常吃力也比较烦躁,不过这个烂骨头也要啃阿,放过去可能就少学会一点东西。
首先咱们看到代码1-5中调用了InvokeActionWithExceptionFilters()方法,也就是代码1-6,那咱们就看看这个InvokeActionWithExceptionFilters()方法,在个InvokeActionWithExceptionFilters()方法中有四个参数,第一个参数是Task<HttpResponseMessage>类型的,这里打住不往下看了,回到代码1-5中调用个InvokeActionWithExceptionFilters()方法的时候,咱们看代码的最后部分依次往前推,最后发现
代码1-9
InvokeActionWithAuthorizationFilters(actionContext, cancellationToken, authorizationFilters, ()=>actionDescriptor.ActionBinding.ExecuteBindingAsync(actionContext, cancellationToken).Then<HttpResponseMessage>(delegate { this._modelState=actionContext.ModelState; returnInvokeActionWithActionFilters(actionContext, cancellationToken, actionFilters, () =>controllerServices.GetActionInvoker().InvokeActionAsync(actionContext, cancellationToken))(); }, newCancellationToken(), false))(),
发现代码1-9的部分就是InvokeActionWithExceptionFilters()方法的参数,咱们看命名也都知道InvokeActionWithExceptionFilters()方法执行的是异常过滤器的内容,第一个参数类型也说过了是Task<HttpResponseMessage>说明在这以前操做已经处理完成了不论是成功了仍是有异常了咱先无论,反正代码1-9最后生成返回的就是Task<HttpResponseMessage>类型的实例,那咱们就来拆开代码1-9.
从代码1-9中能够看到首先调用的是代码1-7的内容也就是调用了InvokeActionWithAuthorizationFilters()方法,咱们看一下代码1-7.
首先代码1-7中的方法有四个参数(HttpActionContext actionContext,CancellationToken cancellationToken, IEnumerable<IAuthorizationFilter>filters, Func<Task<HttpResponseMessage>> innerAction),第一个控制器方法执行上下文对象,跟HttpControllerContext性质都是同样的,不说这个,第二个CancellationToken用于并行开发在并行的任务中,能够把这个类型想象成一个钩子,你能够设置这个钩子的状态和行为,在任务中遇到你的钩子会根据你的钩子作一些操做能够是继续任务能够是终止任务额外再执行一些其余操做(不知道理解的对不对没深刻过,有误的话望你们指正谢谢),至于第三个参数,就是受权过滤器集合类型了,在上面说到的FilterGrouping类型中的AuthorizationFilters属性就是用在这里,第四个参数就比较重要了,这是一个返回Task<HttpResponseMessage>类型的委托,如今咱们把代码1-9也就是调用了InvokeActionWithAuthorizationFilters()方法的代码中的第四个参数剥出来,而后再看下面的代码。
代码1-10
InvokeActionWithAuthorizationFilters ( actionContext, cancellationToken, authorizationFilters,)()
从上面说的也知道如今的代码1-10的部分只是返回一个Task<HttpResponseMessage>类型的实例做为代码1-6的第一个参数,按照这样的思路咱们看一下剥离出来的第四个参数。
代码1-11
() =>actionDescriptor.ActionBinding.ExecuteBindingAsync(actionContext, cancellationToken).Then<HttpResponseMessage>(delegate { this._modelState=actionContext.ModelState; returnInvokeActionWithActionFilters(actionContext, cancellationToken, actionFilters, () =>controllerServices.GetActionInvoker().InvokeActionAsync(actionContext, cancellationToken))(); }, newCancellationToken(), false)
在代码1-11里主要会先调用actionDescriptor的ActionBinding属性下的ExecuteBindingAsync()方法,这里的方法就是Model绑定Model验证所在的地方了这个后面的篇幅会讲,有的朋友会发现ExecuteBindingAsync()方法返回的是Task类型,跟上面所说的所需参数的类型是Fun<Task<HttpResponseMessage>>,而这里明显就是Fun<Task>,是不符合的,并且按照逻辑上说也不符合阿,在受权过滤器执行完毕后应该是行为过滤器的执行阿,这里就涉及到了一个Task的扩展方法调用,就是Then<>()方法了。
代码1-12
internalstaticTask<TOuterResult>Then<TOuterResult>(thisTasktask, Func<Task<TOuterResult>>continuation, CancellationTokencancellationToken=newCancellationToken(), boolrunSynchronously=false) { returntask.ThenImpl<Task, TOuterResult>(t=>continuation(), cancellationToken, runSynchronously); }
用有扩展方法的类型是私有的结构类型,这里就不往下深刻了,就在经过这里将Task转换成Task<HttpResponseMessage>类型的。最后咱们在拆一下把这个匿名委托从代码1-11里面剥出来。
代码1-13
delegate { this._modelState=actionContext.ModelState; returnInvokeActionWithActionFilters(actionContext, cancellationToken, actionFilters, () =>controllerServices.GetActionInvoker().InvokeActionAsync(actionContext, cancellationToken))(); }
看到这里有actionContext.ModelState属性值表示Model验证的结果值,而这个this._modelState的this就是当前的ApiController,_modelState字段对应的是ApiController类型中的ModelState值,在这以后调用最后的1-8代码,在上面的1-13中咱们能够看到最后是由什么对象去执行最后的操做的,这个一系列的过程后面篇幅会讲解到。
在这些全部都执行完毕了以后才会执行到代码1-6,最后就是造成最后的代码1-5那样。