ASP.NET Web API 过滤器创建、执行过程(二)

前言

前面一篇中讲解了过滤器执行之前的创建,通过实现IFilterProvider注册到当前的HttpConfiguration里的服务容器中,当然默认的基础服务也是有的,并且根据这些提供程序所获得的的过滤器信息集合进行排序。本篇就会对过滤器在创建完之后所做的一系列操作进行讲解。

ASP.NET Web API 过滤器创建、执行过程(二)

FilterGrouping过滤器分组类型

FilterGrouping类型是ApiController类型中的私有类型,它的作用就如同它的命名一样,用来对过滤器集合进行分组,在上一篇中我们看到,在经过调用HttpActionDescriptor类型的GetFilterPipeline()方法之后回去获取到排序过后的过滤器信息集合Collection<FilterInfo>。下面我们看一下FilterGrouping类型定义:

示例代码1-1

    private class FilterGrouping{// Fieldsprivate List<IActionFilter> _actionFilters = new List<IActionFilter>();private List<IAuthorizationFilter> _authorizationFilters = new List<IAuthorizationFilter>();private List<IExceptionFilter> _exceptionFilters = new List<IExceptionFilter>();// Methodspublic FilterGrouping(IEnumerable<FilterInfo> filters){foreach (FilterInfo info in filters){IFilter instance = info.Instance;Categorize<IActionFilter>(instance, this._actionFilters);Categorize<IAuthorizationFilter>(instance, this._authorizationFilters);Categorize<IExceptionFilter>(instance, this._exceptionFilters);}}private static void Categorize<T>(IFilter filter, List<T> list) where T : class{T item = filter as T;if (item != null){list.Add(item);}}// Propertiespublic IEnumerable<IActionFilter> ActionFilters{get{return this._actionFilters;}}public IEnumerable<IAuthorizationFilter> AuthorizationFilters{get{return this._authorizationFilters;}}public IEnumerable<IExceptionFilter> ExceptionFilters{get{return this._exceptionFilters;}}
}

在代码1-1中我们看到在FilterGrouping类型的构造函数中便会对过滤器信息集合进行分组了,当然了分组的时候是调用FilterGrouping类型中的放吧,在Categorize()方法中就是根据实例的类型来进行判断的,最后由FilterGrouping类型中的三个公共属性来表示分组过后的不同类型的过滤器集合。

过滤器执行过程

在上个篇幅中我们通过示例了解到过滤器管道的生成过程以及结果,我们就来看一下执行的过程,顺带再看下过滤器管道的结果是不是如上篇上所说的那样。

先看服务器端(Selfhost)的代码:

代码1-2

using System.Web.Http.Controllers;
using System.Web.Http.Filters;
using NameSpaceControllerThree;namespace SelfHost
{class Program{static void Main(string[] args){HttpSelfHostConfiguration selfHostConfiguration =new HttpSelfHostConfiguration("http://localhost/selfhost");using (HttpSelfHostServer selfHostServer = new HttpSelfHostServer(selfHostConfiguration)){selfHostServer.Configuration.Routes.MapHttpRoute("DefaultApi", "api/{controller}/{id}", new { id = RouteParameter.Optional });selfHostServer.Configuration.Services.Replace(typeof(IAssembliesResolver),new CustomAssembliesResolver.LoadSpecifiedAssembliesResolver());//添加全局过滤器selfHostServer.Configuration.Filters.Add(new WebAPIController.Filter.CustomConfigurationActionFilterAttribute());selfHostServer.OpenAsync();Console.WriteLine("服务器端服务监听已开启");Console.Read();}}}
} 

这里只有一个添加全局行为过滤器的这么一句代码,其余的部分就不解释了。

然后我们接着看控制器部分,如下示例代码:

代码1-3

namespace NameSpaceControllerThree
{[CustomControllerAuthorizationFilter][CustomControllerActionFilter]public class WriterAndReadController : ApiController{[CustomActionFilter][CustomControllerActionAuthorizationFilter]public string Get(){StringBuilder strBuilder = new StringBuilder();HttpActionDescriptor actionDescriptor = this.Configuration.Services.GetActionSelector().SelectAction(this.ControllerContext);System.Collections.ObjectModel.Collection<FilterInfo> filtersInfo = actionDescriptor.GetFilterPipeline();foreach (var filter in filtersInfo){strBuilder.AppendLine("【FilterName:"+filter.Instance.GetType().Name+",FilterScope:"+filter.Scope.ToString()+"】");}return strBuilder.ToString();}}
}

对于上一篇,这里的修改只是在控制器类型和控制器方法上各自新增了一个授权过滤器,下面我们就来看一下过滤器的定义,如下示例代码:

代码1-4

/// <summary>/// 全局的行为过滤器/// </summary>public class CustomConfigurationActionFilterAttribute : FilterAttribute, IActionFilter{public Task<System.Net.Http.HttpResponseMessage> ExecuteActionFilterAsync(System.Web.Http.Controllers.HttpActionContext actionContext, System.Threading.CancellationToken cancellationToken, Func<Task<System.Net.Http.HttpResponseMessage>> continuation){Console.WriteLine(this.GetType().Name);return continuation();}}/// <summary>/// 控制器级行为过滤器/// </summary>public class CustomControllerActionFilterAttribute : FilterAttribute, IActionFilter{public Task<System.Net.Http.HttpResponseMessage> ExecuteActionFilterAsync(System.Web.Http.Controllers.HttpActionContext actionContext, System.Threading.CancellationToken cancellationToken, Func<Task<System.Net.Http.HttpResponseMessage>> continuation){Console.WriteLine(this.GetType().Name);return continuation();}}/// <summary>/// 控制器方法级行为过滤器/// </summary>public class CustomActionFilterAttribute : FilterAttribute, IActionFilter{public Task<System.Net.Http.HttpResponseMessage> ExecuteActionFilterAsync(System.Web.Http.Controllers.HttpActionContext actionContext, System.Threading.CancellationToken cancellationToken, Func<Task<System.Net.Http.HttpResponseMessage>> continuation){Console.WriteLine(this.GetType().Name);return continuation();}}/// <summary>/// 控制器级授权访问过滤器/// </summary>public class CustomControllerAuthorizationFilterAttribute : FilterAttribute, IAuthorizationFilter{public Task<System.Net.Http.HttpResponseMessage> ExecuteAuthorizationFilterAsync(System.Web.Http.Controllers.HttpActionContext actionContext, System.Threading.CancellationToken cancellationToken, Func<Task<System.Net.Http.HttpResponseMessage>> continuation){Console.WriteLine(this.GetType().Name);return continuation();}}/// <summary>/// 控制器方法级授权访问过滤器/// </summary>public class CustomControllerActionAuthorizationFilterAttribute : FilterAttribute, IAuthorizationFilter{public Task<System.Net.Http.HttpResponseMessage> ExecuteAuthorizationFilterAsync(System.Web.Http.Controllers.HttpActionContext actionContext, System.Threading.CancellationToken cancellationToken, Func<Task<System.Net.Http.HttpResponseMessage>> continuation){Console.WriteLine(this.GetType().Name);return continuation();}
}

在代码1-4中,我们可以看到代码1-3中所有使用到的过滤器类型和代码1-2中添加全局过滤器类型。

现在我们看一下最后的结果

图1

黑色框的结果为SelfHost服务器端过滤器执行过程的输出,在代码1-4中我们可以看到,这个得出的一个结论是授权过滤器不管是什么应用范围的都是优于行为过滤器的,而在同一种类型的过滤器中是根据应用范围来确定执行顺序的,这个跟下面的浏览器里的内容有点关系,浏览器里显示的就是所有过滤器在排序后的管道里的样子,可以看到管道里单纯的就是按照应用范围的级别来排序的,至于这个过滤器是什么类型在处理排序的时候则是一点都不关心的。

过滤器执行过程-代码分析

首先看一下如下示意图,可以代表了在控制器执行的过程中过滤器的执行过程。

图2

上面通过示例来说明了过滤器的执行过程,现在我们来看一下在框架的源码中是什么样的,因为在过滤器执行过程中还包含了其它方面的知识点,所以这个是迟早都要看的,下面我们就来看一下吧。

代码1-5

     return InvokeActionWithExceptionFilters(InvokeActionWithAuthorizationFilters(actionContext, cancellationToken, authorizationFilters, () => actionDescriptor.ActionBinding.ExecuteBindingAsync(actionContext, cancellationToken).Then<HttpResponseMessage>(delegate {this._modelState = actionContext.ModelState;return InvokeActionWithActionFilters(actionContext, cancellationToken, actionFilters, () => controllerServices.GetActionInvoker().InvokeActionAsync(actionContext, cancellationToken))();}, new CancellationToken(), false))(), actionContext, cancellationToken, exceptionFilters);

在代码1-5中涉及到三个静态方法,我们先来看一下:

InvokeActionWithExceptionFilters()

InvokeActionWithAuthorizationFilters()

InvokeActionWithActionFilters()

示例代码如下:

代码1-6

    internal static Task<HttpResponseMessage> InvokeActionWithExceptionFilters(Task<HttpResponseMessage> actionTask, HttpActionContext actionContext, CancellationToken cancellationToken, IEnumerable<IExceptionFilter> filters){return actionTask.Catch<HttpResponseMessage>(delegate (CatchInfo<HttpResponseMessage> info) {HttpActionExecutedContext executedContext = new HttpActionExecutedContext(actionContext, info.Exception);filters = filters.Reverse<IExceptionFilter>();IEnumerable<Task> asyncIterator = from filter in filters select filter.ExecuteExceptionFilterAsync(executedContext, cancellationToken);bool runSynchronously = true;Task<HttpResponseMessage> task = TaskHelpers.Iterate(asyncIterator, cancellationToken, true).Then<HttpResponseMessage>(delegate {if (executedContext.Response != null){return TaskHelpers.FromResult<HttpResponseMessage>(executedContext.Response);}return TaskHelpers.FromError<HttpResponseMessage>(executedContext.Exception);}, new CancellationToken(), runSynchronously);return info.Task(task);}, new CancellationToken());}

代码1-7

    internal static Func<Task<HttpResponseMessage>> InvokeActionWithAuthorizationFilters(HttpActionContext actionContext, CancellationToken cancellationToken, IEnumerable<IAuthorizationFilter> filters, Func<Task<HttpResponseMessage>> innerAction){filters = filters.Reverse<IAuthorizationFilter>();return filters.Aggregate<IAuthorizationFilter, Func<Task<HttpResponseMessage>>>(innerAction, (continuation, filter) => () => filter.ExecuteAuthorizationFilterAsync(actionContext, cancellationToken, continuation));}

代码1-8

    internal static Func<Task<HttpResponseMessage>> InvokeActionWithActionFilters(HttpActionContext actionContext, CancellationToken cancellationToken, IEnumerable<IActionFilter> filters, Func<Task<HttpResponseMessage>> innerAction){filters = filters.Reverse<IActionFilter>();return filters.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;return InvokeActionWithActionFilters(actionContext, cancellationToken, actionFilters, () => controllerServices.GetActionInvoker().InvokeActionAsync(actionContext, cancellationToken))();}, new CancellationToken(), 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;return InvokeActionWithActionFilters(actionContext, cancellationToken, actionFilters, () => controllerServices.GetActionInvoker().InvokeActionAsync(actionContext, cancellationToken))();}, new CancellationToken(), false)

在代码1-11里主要会先调用actionDescriptor的ActionBinding属性下的ExecuteBindingAsync()方法,这里的方法就是Model绑定Model验证所在的地方了这个后面的篇幅会讲,有的朋友会发现ExecuteBindingAsync()方法返回的是Task类型,跟上面所说的所需参数的类型是Fun<Task<HttpResponseMessage>>,而这里明显就是Fun<Task>,是不符合的,而且按照逻辑上说也不符合阿,在授权过滤器执行完毕后应该是行为过滤器的执行阿,这里就涉及到了一个Task的扩展方法调用,就是Then<>()方法了。

代码1-12

internal static Task<TOuterResult> Then<TOuterResult>(this Task task, Func<Task<TOuterResult>> continuation, CancellationToken cancellationToken = new CancellationToken(), bool runSynchronously = false)
{return task.ThenImpl<Task, TOuterResult>(t => continuation(), cancellationToken, runSynchronously);
}

用有扩展方法的类型是私有的结构类型,这里就不往下深入了,就在通过这里将Task转换成Task<HttpResponseMessage>类型的。最后我们在拆一下把这个匿名委托从代码1-11里面剥出来。

代码1-13

delegate {this._modelState = actionContext.ModelState;return InvokeActionWithActionFilters(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那样。

作者:金源

出处:http://www.cnblogs.com/jin-yuan/

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面

转载于:https://www.cnblogs.com/jin-yuan/p/3971369.html

ASP.NET Web API 过滤器创建、执行过程(二)相关推荐

  1. ASP.NET Web API 控制器创建过程

    前言 本来这篇随笔应该是在上周就该写出来发布的,由于身体跟不上节奏感冒发烧有心无力,这种天气感冒发烧生不如死,也真正的体会到了什么叫病来如山倒,病去如抽丝.这两天状态才好了一点,让我理解了什么才是革命 ...

  2. ASP.NET Web API 2 过滤器

    Ø  前言 我们知道 ASP.NET Web API 过滤器,也是属于消息处理机制中的一部分.正因如此,我们经常使用它来完成对请求的授权验证.参数验证,以及请求的 Log 记录,程序异常捕获等. 1. ...

  3. 恶梦护士 asa_噩梦就是JSON日期。 另外,JSON.NET和ASP.NET Web API

    恶梦护士 asa Ints are easy. Strings are mostly easy. Dates? A nightmare. They always will be. There's di ...

  4. 【Web API系列教程】1.1 — ASP.NET Web API入门

    前言 HTTP不仅仅服务于web页面,同时也是构建暴露服务和数据的API的强大平台.HTTP有着简单.灵活和无处不在的特点.你能想到的几乎所有平台都包含有一个HTTP库,所以HTTP服务可以遍及广泛的 ...

  5. 【Web API系列教程】1.3 — 实战:用ASP.NET Web API和Angular.js创建单页面应用程序(上)

    前言 在传统的web应用程序中,客户端(浏览器)通过请求页面来启动与服务器的通信.然后服务器处理该请求,并发送HTML页面到客户端.在随后页面上的操作中--例如,用户导航到一个链接或提交一个包含数据的 ...

  6. 【ASP.NET Web API教程】2.3.5 用Knockout.js创建动态UI

    [ASP.NET Web API教程]2.3.5 用Knockout.js创建动态UI 原文:[ASP.NET Web API教程]2.3.5 用Knockout.js创建动态UI 注:本文是[ASP ...

  7. ASP.NET Web API的Controller是如何被创建的?

    Web API调用请求的目标是定义在某个HttpController类型中的某个Action方法,所以消息处理管道最终需要激活目标HttpController对象.调用请求的URI会携带目标HttpC ...

  8. 【ASP.NET Web API教程】2.3.3 创建Admin控制器

    原文:[ASP.NET Web API教程]2.3.3 创建Admin控制器 注:本文是[ASP.NET Web API系列教程]的一部分,如果您是第一次看本博客文章,请先看前面的内容. Part 3 ...

  9. Web API 2 入门——创建ASP.NET Web API的帮助页面(谷歌翻译)

    在这篇文章中 创建API帮助页面 将帮助页面添加到现有项目 添加API文档 在敞篷下 下一步 作者:Mike Wasson 创建Web API时,创建帮助页面通常很有用,以便其他开发人员知道如何调用A ...

最新文章

  1. bitnami redmine mysql_centos7 BitNami一键安装Redmine
  2. apache使用.htaccess删除.html扩展名_Web前端入门:html元素解析
  3. 每日一皮:客户被绑,蒙眼,惊问 “想干什么?”
  4. SHA256安全散列算法
  5. 「 每日一练,快乐水题 」1189. “气球” 的最大数量
  6. Java8新特性之stream的详细用法
  7. Linux 编译 libc log,在Android的源码中添加LOG
  8. java socket 编程 客户机服务器_Java Socket编程服务器响应客户端实例代码
  9. vm虚拟机win10无法复制文件_远程桌面无法复制粘贴传输文件解决办法
  10. HDU2093 考试排名【排序】
  11. mt4交易系统源码_如何将源码加载到mt4里面
  12. 集成显卡连接显示器的线跟独立显卡的不同么,分别叫什么
  13. 德保罗大学计算机科学专业,德保罗大学专业
  14. 【时空序列】使用3D卷积网络学习时空特征
  15. ES6 Javascript Nodejs Mindmap
  16. (已解决)解决第三方平台访问Vue项目cue-router把#号变成百分号23导致项目404的问题
  17. Kinect(XBOX360)相机在ROS下标定
  18. 一台电脑登陆两个微信账号
  19. 计算机视觉之边缘提取
  20. epub格式电子书剖析之一:文档构成

热门文章

  1. 欧洲两个研究团队开发出了让截肢者能感觉到并准确抓住物体的仿生手
  2. Science:若DTC基因检测达2%成年人群,几乎所有人的身份或将无所遁形
  3. 美国12大科技公司如何参与自动驾驶?
  4. “六成应用开发不需要程序员”喜提热搜背后,RPA 会抢饭碗吗?
  5. 漫画设计模式:什么是 “装饰器模式” ?
  6. 32岁前平凡无奇,鼓动同事创业,最终逆袭成硅谷首富
  7. 从开源小白到 Apache Member,我的成长之路
  8. java线程同步以及对象锁和类锁解析(多线程synchronized关键字)
  9. java反射中,Class.forName和classloader的区别
  10. p2148 [SDOI2009]ED