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调用一致。

原文地址:https://www.cnblogs.com/majiang/p/2802782.html