Asp.net web Api源碼分析-Filter


緊接着上文Asp.net web Api源碼分析-HttpActionDescriptor的創建 HttpActionDescriptor現在已經創建好了,在這里個人再次提醒一下,建議大家在路由的時候寫上Action參數,如

api/{controller}/{action}/{id}而不要忽略Action參數寫成api/{controller}/{id}。現在我們回到ApiController的ExecuteAsync方法中來,接下來就是利用新建的HttpActionDescriptor來創建一個HttpActionContext實例,然后通過 IEnumerable<FilterInfo> filters = actionDescriptor.GetFilterPipeline();來獲取FilterInfo的集合。那么我們來看看FilterInfo是如何獲取的,在HttpActionDescriptor中有一個InitializeFilterPipeline方法,相關代碼如下:

    public abstract class HttpActionDescriptor
    {
         protected HttpActionDescriptor()
        {
            _filterPipeline = new Lazy<Collection<FilterInfo>>(InitializeFilterPipeline);
        }
       public virtual Collection<FilterInfo> GetFilterPipeline()
        {
            return _filterPipeline.Value;
        }
         private Collection<FilterInfo> InitializeFilterPipeline()
        {
            IEnumerable<IFilterProvider> filterProviders = _configuration.Services.GetFilterProviders();

            IEnumerable<FilterInfo> filters = filterProviders.SelectMany(fp => fp.GetFilters(_configuration, this)).OrderBy(f => f, FilterInfoComparer.Instance);

            // Need to discard duplicate filters from the end, so that most specific ones get kept (Action scope) and
            // less specific ones get removed (Global)
            filters = RemoveDuplicates(filters.Reverse()).Reverse();

            return new Collection<FilterInfo>(filters.ToList());
        }
    }

在DefaultServices中有如下一句代碼:SetMultiple<IFilterProvider>(new ConfigurationFilterProvider(),new ActionDescriptorFilterProvider());所以我們知道filterProviders這里其實是ConfigurationFilterProvider、ActionDescriptorFilterProvider組成的一個集合。然后依次調用他們的GetFilters方法,其中ConfigurationFilterProvider中的GetFilters方法非常簡單就是調用configuration.Filters屬性,可見這個是一個全局的Filter,默認的configuration.Filters是沒有成員的,如果我們需要注冊一個自定義的全局的Filter,我們可以在WebApiConfig的Register方法中添加 config.Filters.Add(new XXX());現在我們來看看ActionDescriptorFilterProvider的GetFilters是如何實現的:

public IEnumerable<FilterInfo> GetFilters(HttpConfiguration configuration, HttpActionDescriptor actionDescriptor)
        {
            IEnumerable<FilterInfo> controllerFilters = actionDescriptor.ControllerDescriptor.GetFilters().Select(instance => new FilterInfo(instance, FilterScope.Controller));
            IEnumerable<FilterInfo> actionFilters = actionDescriptor.GetFilters().Select(instance => new FilterInfo(instance, FilterScope.Action));
            return controllerFilters.Concat(actionFilters);

        }

這里主要是獲取Controller和Action的Filter然后把他們合並成一個filter集合,Controller和Action的 filter的獲取方式都一樣,主要是獲取他們的IFilter特性,然后通過該特性實例創建一個新的FilterInfo實例。這里的 FilterScope仍然是Global>Controller>Action,默認直接實現或者繼承IFilter的有 IActionFilter、IAuthorizationFilter、IExceptionFilter\、FilterAttribute,實際開 發中主要的FilterAttribute有以下幾個,

public abstract class ActionFilterAttribute : FilterAttribute, IActionFilter
public abstract class AuthorizationFilterAttribute : FilterAttribute, IAuthorizationFilter
public class AuthorizeAttribute : AuthorizationFilterAttribute
public abstract class ExceptionFilterAttribute : FilterAttribute, IExceptionFilter
public abstract class ExceptionFilterAttribute : FilterAttribute, IExceptionFilter

現在回到HttpActionDescriptor的InitializeFilterPipeline方法中來,這里已經獲取到 FilterInfo的集合,同時也調用了一個RemoveDuplicates方法來去掉重復的FilterInfo,去掉重復的原則是調用 FilterInfo的AllowMultiple屬性。

現在我們回到ApiController的ExecuteAsync方法中來,已經獲取到了FilterInfo集合,然后利用他們來創建一個 FilterGrouping實例,說白了就是把這些FilterInfo分成三個組,按照他們的類型分別分為IActionFilter、 IAuthorizationFilter、IExceptionFilter組。接下倆主要就是執行這些Filter,首先執行的是 authorizationFilters組中的filter,調用每個filter的ExecuteAuthorizationFilterAsync 方法,在調用完后在調用這里的continuation方法。在continuation主要負責是綁定Action參數,然后再依次 actionFilters數組中每個filter的ExecuteActionFilterAsync方法,這里的調用代碼技巧句不說了,和mvc代碼 一致。

總之web api的filter調用和mvc中filter調用一致。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM