ASP.NET Web API 过滤器创建、执行过程(二)
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 过滤器创建、执行过程(二)的更多相关文章
- ASP.NET Web API 过滤器创建、执行过程(一)
ASP.NET Web API 过滤器创建.执行过程(一) 前言 在上一篇中我们讲到控制器的执行过程系列,这个系列要搁置一段时间了,因为在控制器执行的过程中包含的信息都是要单独的用一个系列来描述的,就 ...
- ASP.NET Web API 控制器创建过程(二)
ASP.NET Web API 控制器创建过程(二) 前言 本来这篇随笔应该是在上周就该写出来发布的,由于身体跟不上节奏感冒发烧有心无力,这种天气感冒发烧生不如死,也真正的体会到了什么叫病来如山倒,病 ...
- ASP.NET Web API 控制器创建过程(一)
ASP.NET Web API 控制器创建过程(一) 前言 在前面对管道.路由有了基础的了解过后,本篇将带大家一起学习一下在ASP.NET Web API中控制器的创建过程,这过程分为几个部分下面的内 ...
- 使用ASP.NET Web API 2创建OData v4 终结点
开放数据协议(Open Data Protocol[简称OData])是用于Web的数据访问协议.OData提供了一种对数据集进行CRUD操作(Create,Read,Update,Delete)的统 ...
- [转]使用ASP.NET Web API 2创建OData v4 终结点
本文转自:http://www.cnblogs.com/farb/p/ODataAspNetWebAPI.html 开放数据协议(Open Data Protocol[简称OData])是用于Web的 ...
- ASP.NET Web API 2 过滤器
Ø 前言 我们知道 ASP.NET Web API 过滤器,也是属于消息处理机制中的一部分.正因如此,我们经常使用它来完成对请求的授权验证.参数验证,以及请求的 Log 记录,程序异常捕获等. 1. ...
- 使用ASP.NET web API创建REST服务(二)
Creating a REST service using ASP.NET Web API A service that is created based upon the architecture ...
- 使用ASP.NET web API创建REST服务(三)
本文档来源于:http://www.cnblogs.com/madyina/p/3390773.html Creating a REST service using ASP.NET Web API A ...
- 剖析Asp.Net Web API中HttpController的激活
在Asp.Net Web API中,请求的目标是定义在某个HttpController中的某个Action方法.当请求经过Asp.Net Web API消息处理管道到达管道"龙尾" ...
随机推荐
- Mapreduce的文件和hbase共同输入
Mapreduce的文件和hbase共同输入 package duogemap; import java.io.IOException; import org.apache.hadoop.co ...
- .NET Core的日志[2]:将日志输出到控制台
对于一个控制台应用,比如采用控制台应用作为宿主的ASP.NET Core应用,我们可以将记录的日志直接输出到控制台上.针对控制台的Logger是一个类型为ConsoleLogger的对象,Consol ...
- Entity Framework 手动使用migration里面的up 和down方法。
add-migration -IgnoreChanges 201606100717405_201606100645298_InitialCreate 执行这一句后 ,清空使用map生成的代码,个人不太 ...
- StatePattern(状态模式)
/** * 状态模式 * @author TMAC-J * 状态模式和策略模式很像,其实仔细研究发现完全不一样 * 策略模式各策略之间没有任何关系,独立的 * 状态模式各状态之间接口方法都是一样的 * ...
- webpack学习总结
前言 在还未接触webpack,就有几个疑问: 1. webpack本质上是什么? 2. 跟异步模块加载有关系吗? 3. 可否生成多个文件,一定是一个? 4. 被引用的文件有其他异步加载模块怎么办? ...
- sql 删除表中的重复记录
嗯,遇见了表中存在重复的记录的问题,直接写sql删除时最快的,才不要慢慢的复制到excel表中慢慢的人工找呢.哼. 如下sql,找出重复的记录,和重复记录中ID值最小的记录(表中ID为自增长) sel ...
- 笔记:Memory Notification: Library Cache Object loaded into SGA
笔记:Memory Notification: Library Cache Object loaded into SGA在警告日志中发现一些这样的警告信息:Mon Nov 21 14:24:22 20 ...
- js实现四大经典排序算法
为了方便测试,这里写了一个创建长度为n的随机数组 function createArr(n) { var arr = []; while (n--) { arr.push(~~(Math.random ...
- python_单元测试unittest
Python自带一个单元测试框架是unittest模块,用它来做单元测试,它里面封装好了一些校验返回的结果方法和一些用例执行前的初始化操作. 步骤1:首先引入unittest模块--import un ...
- D3.js学习(七)
上一节中我们学会了如何旋转x轴标签以及自定义标签内容,在这一节中,我们将接触动画(transition) 首先,我们要在页面上添加一个按钮,当我们点击这个按钮时,调用我们的动画.所以,我们还需要在原来 ...