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/

时间: 2024-07-28 13:33:30

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

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

前言 在上一篇中我们讲到控制器的执行过程系列,这个系列要搁置一段时间了,因为在控制器执行的过程中包含的信息都是要单独的用一个系列来描述的,就如今天的这个篇幅就是在上面内容之后所看到的一个知识要点之一. ASP.NET Web API 过滤器创建.执行过程(一) 下面就来讲解一下在ASP.NET Web API框架中过滤器的创建.执行过程. 过滤器所在的位置 图1 图1所示的就是控制器执行过程很粗略的表示. 通过上一篇内容我们了解到控制器方法选择器最后返回的并不是控制器方法,而是对于控制器方法描述

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

ASP.NET Web API 控制器创建过程(一) 前言 在前面对管道.路由有了基础的了解过后,本篇将带大家一起学习一下在ASP.NET Web API中控制器的创建过程,这过程分为几个部分下面的内容会为大家讲解第一个部分,也是ASP.NET Web API框架跟ASP.NET MVC框架实现上存在不同的一部分. 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 终结点

本文转自:http://www.cnblogs.com/farb/p/ODataAspNetWebAPI.html 开放数据协议(Open Data Protocol[简称OData])是用于Web的数据访问协议.OData提供了一种对数据集进行CRUD操作(Create,Read,Update,Delete)的统一方式.Asp.Net Web API支持该协议的v3 和v4版,甚至可以创建一个和v3终结点并排运行的v4终结点.该博文演示了如何创建支持CRUD操作的OData v4终结点. 用到

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

前言 HTTP不仅仅服务于web页面.同一时候也是构建暴露服务和数据的API的强大平台.HTTP有着简单.灵活和无处不在的特点.你能想到的差点儿全部平台都包括有一个HTTP库.所以HTTP服务能够遍及广泛的client,包括浏览器.移动设备和传统桌面应用程序. ASP.NET Web API是一个在.NET框架上构建web API的框架.在本教程中,你将使用ASP.NET Web API来创建一个返回产品列表的web API. 创建Web API项目 在本教程中,你将使用ASP.NET Web

通过Knockout.js + ASP.NET Web API构建一个简单的CRUD应用

REFERENCE FROM : http://www.cnblogs.com/artech/archive/2012/07/04/Knockout-web-api.html 较之面向最终消费者的网站,企业级Web应用对用户体验的要求要低一些.不过客户对“用户体验”的要求是“与日俱增”的,很多被“惯坏了”的用户已经不能忍受Postback带来的页面刷新,所以Ajax在企业级Web应用中得到了广泛的应用.企业级Web应用的一个特点是以“数据处理”为主,所以“面向绑定”的Knockout.js 是一

开始 ASP.NET Web API 2 之旅

HTTP不仅仅是提供网页而已.它同时也是一个用于公开服务和数据的强大的API平台.HTTP简单.灵活,而且无处不在.你能想到的几乎所有的平台,都会有一个HTTP库,因此HTTP服务可以达到广泛的客户端,包括浏览器.移动设备,和传统的桌面应用程序. ASP.NET Web API是一个用于构建基于.NET Framework 的 Web API 的框架.在本教程中,你将会使用ASP.NET Web API来创建返回一个产品列表的web API. 教程中使用的软件有: Visual Studio 2

ASP.NET Web API 2 入门(一)

前言 HTTP 不是只是为了服务的 web 页.这也是建设公开服务和数据的 Api 的强大平台.HTTP 是简单的. 灵活的和无处不在.你能想到的几乎任何平台有 HTTP 库,因此,HTTP 服务可以达到范围广泛的客户,包括浏览器. 移动设备和传统的桌面应用程序. ASP.NET Web API 是一个用于构建 web Api 在.NET 框架上框架.在本教程中,您将使用 ASP.NET Web API 来创建一个 web API 返回的产品列表. 创建一个 Web API 项目 在本教程中,您

01Getting Started---Getting Started with ASP.NET Web API 2入门WebApi2

HTTP 不只是为了生成 web 页面.它也是建立公开服务和数据的 Api 的强大平台.HTTP 是简单的. 灵活的和无处不在.你能想到的几乎任何平台有 HTTP 库,因此,HTTP 服务可以达到范围广泛的客户,包括浏览器. 移动设备和传统的桌面应用程序. ASP.NET Web API 是用于生成 web Api 在.NET 框架上的框架.在本教程中,您将使用 ASP.NET Web API 来创建 web API 返回的产品列表. 在本教程中使用的软件版本 视觉工作室 2013 年 Web