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

前言

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

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

FilterGrouping过滤器分组类型

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

示例代码1-1

    private class FilterGrouping
{
// Fields
private List<IActionFilter> _actionFilters = new List<IActionFilter>();
private List<IAuthorizationFilter> _authorizationFilters = new List<IAuthorizationFilter>();
private List<IExceptionFilter> _exceptionFilters = new List<IExceptionFilter>(); // Methods
public 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);
}
} // Properties
public 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/

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

ASP.NET Web API 过滤器创建、执行过程(二)的更多相关文章

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

    ASP.NET Web API 过滤器创建.执行过程(一) 前言 在上一篇中我们讲到控制器的执行过程系列,这个系列要搁置一段时间了,因为在控制器执行的过程中包含的信息都是要单独的用一个系列来描述的,就 ...

  2. ASP.NET Web API 控制器创建过程(二)

    ASP.NET Web API 控制器创建过程(二) 前言 本来这篇随笔应该是在上周就该写出来发布的,由于身体跟不上节奏感冒发烧有心无力,这种天气感冒发烧生不如死,也真正的体会到了什么叫病来如山倒,病 ...

  3. ASP.NET Web API 控制器创建过程(一)

    ASP.NET Web API 控制器创建过程(一) 前言 在前面对管道.路由有了基础的了解过后,本篇将带大家一起学习一下在ASP.NET Web API中控制器的创建过程,这过程分为几个部分下面的内 ...

  4. 使用ASP.NET Web API 2创建OData v4 终结点

    开放数据协议(Open Data Protocol[简称OData])是用于Web的数据访问协议.OData提供了一种对数据集进行CRUD操作(Create,Read,Update,Delete)的统 ...

  5. [转]使用ASP.NET Web API 2创建OData v4 终结点

    本文转自:http://www.cnblogs.com/farb/p/ODataAspNetWebAPI.html 开放数据协议(Open Data Protocol[简称OData])是用于Web的 ...

  6. ASP.NET Web API 2 过滤器

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

  7. 使用ASP.NET web API创建REST服务(二)

    Creating a REST service using ASP.NET Web API A service that is created based upon the architecture ...

  8. 使用ASP.NET web API创建REST服务(三)

    本文档来源于:http://www.cnblogs.com/madyina/p/3390773.html Creating a REST service using ASP.NET Web API A ...

  9. 剖析Asp.Net Web API中HttpController的激活

    在Asp.Net Web API中,请求的目标是定义在某个HttpController中的某个Action方法.当请求经过Asp.Net Web API消息处理管道到达管道"龙尾" ...

随机推荐

  1. [ 高并发]Java高并发编程系列第二篇--线程同步

    高并发,听起来高大上的一个词汇,在身处于互联网潮的社会大趋势下,高并发赋予了更多的传奇色彩.首先,我们可以看到很多招聘中,会提到有高并发项目者优先.高并发,意味着,你的前雇主,有很大的业务层面的需求, ...

  2. Linux碎碎念

    在学习Linux过程中,有许多有用的小技巧.如果放在纸质的笔记本上,平时查阅会相当不方便.现在以一种“碎碎念”的方式,汇集整理在此,目前还不是很多,但随着学习.工作的深入,后续会陆陆续续添加更多的小技 ...

  3. unity 3d 解析 json

    官网案例传送门 我这里不过是借花献佛,案例官网就有. using UnityEngine; using System.Collections; public class json : MonoBeha ...

  4. the Zen of Python---转载版

    摘自译文学习区 http://article.yeeyan.org/view/legendsland/154430 The Zen of Python Python 之禅 Beautiful is b ...

  5. jenkins无法重启tomcat的原因

    在使用Hudson的执行sh脚本的时候,如果sh脚本是一个后台进程,如 Tomcat 这样的服务.如果使用Hudson的默认配置,会发现这些sh 进程有启动的过程,但是不会常驻后台,看Hudson 输 ...

  6. 记:MySQL 5.7.3.0 安装 全程截图

    前言: 下一个班快讲MySQL数据库了,正好把服务器里面的MySQL卸了重装了一下. 截个图,作为笔记.也正好留给需要的朋友们. 目录: 下载软件 运行安装程序 安装程序欢迎界面 许可协议 查找更新 ...

  7. Linux程序包管理之rpm

    rpm简介 rpm( Red Hat Package Manager )是一个开放的软件包管理系统.它工作于Red Hat Linux及其他Linux系统,成为Linux中公认的软件包管理标准. rp ...

  8. 支付宝web支付

    过程 1. 用户下单 2. 商户后台产生订单 3. 请求支付宝web支付页面(将订单信息返回给用户---放在form里面---隐藏起来-----并通过脚本自动提交此form到支付宝web支付页) 4. ...

  9. Visual Studio 2015正式发布

    Windows 10 RTM正式版要7月29日发布,微软的另一个重磅软件Visual Studio 2015已经率先发布,今天如期放出了正式版本.Visual Studio 2015包括许多新功能和更 ...

  10. .NET面试题系列[6] - 反射

    反射 - 定义,实例与优化 在面试中,通常会考察反射的定义(操作元数据),可以用反射做什么(获得程序集及其各个部件),反射有什么使用场景(ORM,序列化,反序列化,值类型比较等).如果答得好,还可能会 ...