ASP.NET Web API 過濾器建立、執行過程(二)

ASP.NET Web API 過濾器建立、執行過程(二)

前言

前面一篇中講解了過濾器執行以前的建立,經過實現IFilterProvider註冊到當前的HttpConfiguration裏的服務容器中,固然默認的基礎服務也是有的,而且根據這些提供程序所得到的的過濾器信息集合進行排序。本篇就會對過濾器在建立完以後所作的一系列操做進行講解。api

 

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類型中的三個公共屬性來表示分組事後的不一樣類型的過濾器集合。框架

 

過濾器執行過程

在上個篇幅中咱們經過示例瞭解到過濾器管道的生成過程以及結果,咱們就來看一下執行的過程,順帶再看下過濾器管道的結果是否是如上篇上所說的那樣。async

先看服務器端(Selfhost)的代碼:ide

代碼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();
            }
        }
    }
} 

這裏只有一個添加全局行爲過濾器的這麼一句代碼,其他的部分就不解釋了。ui

而後咱們接着看控制器部分,以下示例代碼:this

代碼1-3spa

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/

本文版權歸做者和博客園共有,歡迎轉載,但未經做者贊成必須保留此段聲明,且在文章頁面

相關文章
相關標籤/搜索