zoukankan      html  css  js  c++  java
  • ASP.NET MVC5学习笔记之Filter提供体系

      前面我们介绍了Filter的基本使用,但各种Filter要在合适的时机运行起来,需要预先准备好,现在看看ASP.NET MVC框架是怎么做的。

    一.Filter集合

      在ControlerActionInvoker的InvokeAction方法中,只有一行代码FilterInfo filterInfo = GetFilters(controllerContext, actionDescriptor), 把收集的Filter信息放到了FilterInfo中,我们来看看

    访类型的定义:

     1  public class FilterInfo
     2     {
     3         
     4         public FilterInfo();
     5       
     6         public FilterInfo(IEnumerable<Filter> filters);
     7 
     8        
     9         public IList<IActionFilter> ActionFilters { get; }
    10         public IList<System.Web.Mvc.Filters.IAuthenticationFilter> AuthenticationFilters { get; }
    11        
    12         public IList<IAuthorizationFilter> AuthorizationFilters { get; }
    13       
    14         public IList<IExceptionFilter> ExceptionFilters { get; }
    15    
    16         public IList<IResultFilter> ResultFilters { get; }
    17     }
    View Code

        可以看到,这个类型定义的5种系统Filter集合信息. 来看看它带参的构造函数:

     public FilterInfo(IEnumerable<Filter> filters)
            {
                // Determine the override scope for each filter type and cache the filters list.
                OverrideFilterInfo processed = ProcessOverrideFilters(filters);
                // Split the cached filters list based on filter type and override scope.
                SplitFilters(processed);
            }

      可以看到分两步:

        1 .ProcessOverrideFilters处理前面的提到IOverrideFilter接口

      2. 从列表中把Filter分离到各自的Filter接口集合 

      ProcessOverrideFilters方法的代码如下:

     1 private static OverrideFilterInfo ProcessOverrideFilters(IEnumerable<Filter> filters)
     2         {
     3             OverrideFilterInfo result = new OverrideFilterInfo
     4             {
     5                 ActionOverrideScope = FilterScope.First,
     6                 AuthenticationOverrideScope = FilterScope.First,
     7                 AuthorizationOverrideScope = FilterScope.First,
     8                 ExceptionOverrideScope = FilterScope.First,
     9                 ResultOverrideScope = FilterScope.First,
    10                 Filters = new List<Filter>()
    11             };
    12 
    13             // Evaluate the 'filters' enumerable only once since the operation can be quite expensive.
    14             foreach (Filter filter in filters)
    15             {
    16                 if (filter == null)
    17                 {
    18                     continue;
    19                 }
    20                 IOverrideFilter overrideFilter = filter.Instance as IOverrideFilter;
    21 
    22                 if (overrideFilter != null)
    23                 {
    24                     if (overrideFilter.FiltersToOverride == typeof(IActionFilter)
    25                         && filter.Scope >= result.ActionOverrideScope)
    26                     {
    27                         result.ActionOverrideScope = filter.Scope;
    28                     }
    29                     else if (overrideFilter.FiltersToOverride == typeof(IAuthenticationFilter)
    30                         && filter.Scope >= result.AuthenticationOverrideScope)
    31                     {
    32                         result.AuthenticationOverrideScope = filter.Scope;
    33                     }
    34                     else if (overrideFilter.FiltersToOverride == typeof(IAuthorizationFilter)
    35                         && filter.Scope >= result.AuthorizationOverrideScope)
    36                     {
    37                         result.AuthorizationOverrideScope = filter.Scope;
    38                     }
    39                     else if (overrideFilter.FiltersToOverride == typeof(IExceptionFilter)
    40                         && filter.Scope >= result.ExceptionOverrideScope)
    41                     {
    42                         result.ExceptionOverrideScope = filter.Scope;
    43                     }
    44                     else if (overrideFilter.FiltersToOverride == typeof(IResultFilter)
    45                         && filter.Scope >= result.ResultOverrideScope)
    46                     {
    47                         result.ResultOverrideScope = filter.Scope;
    48                     }
    49                 }
    50 
    51                 // Cache filters to avoid having to enumerate it again (expensive). Do so here to avoid an extra loop.
    52                 result.Filters.Add(filter);
    53             }
    54 
    55             return result;
    56         }
    View Code

        这段代码遍历Filter列表,记录实现了IOverrideFilter的Filter的最高OverrideScope, 在下面的SplitFilters处理中,少于OverrideScope的Filter将不会添加到最终的集合中

      SplitFilters方法代码如下:

     1  private void SplitFilters(OverrideFilterInfo info)
     2         {
     3             Contract.Assert(info.Filters != null);
     4 
     5             foreach (Filter filter in info.Filters)
     6             {
     7                 Contract.Assert(filter != null);
     8 
     9                 IActionFilter actionFilter = filter.Instance as IActionFilter;
    10 
    11                 if (actionFilter != null && filter.Scope >= info.ActionOverrideScope)
    12                 {
    13                     _actionFilters.Add(actionFilter);
    14                 }
    15 
    16                 IAuthenticationFilter authenticationFilter = filter.Instance as IAuthenticationFilter;
    17 
    18                 if (authenticationFilter != null && filter.Scope >= info.AuthenticationOverrideScope)
    19                 {
    20                     _authenticationFilters.Add(authenticationFilter);
    21                 }
    22 
    23                 IAuthorizationFilter authorizationFilter = filter.Instance as IAuthorizationFilter;
    24 
    25                 if (authorizationFilter != null && filter.Scope >= info.AuthorizationOverrideScope)
    26                 {
    27                     _authorizationFilters.Add(authorizationFilter);
    28                 }
    29 
    30                 IExceptionFilter exceptionFilter = filter.Instance as IExceptionFilter;
    31 
    32                 if (exceptionFilter != null && filter.Scope >= info.ExceptionOverrideScope)
    33                 {
    34                     _exceptionFilters.Add(exceptionFilter);
    35                 }
    36 
    37                 IResultFilter resultFilter = filter.Instance as IResultFilter;
    38 
    39                 if (resultFilter != null && filter.Scope >= info.ResultOverrideScope)
    40                 {
    41                     _resultFilters.Add(resultFilter);
    42                 }
    43             }
    44         }
    View Code

        实现各个Filter的分离,代码很简单,不再说明。

     二. Filter收集

      在ASP.NET MVC5中最终通过FilterProviders.Providers.GetFilters方法得到所有的Filter列表,我们先来看看FilterProviders这个类型,定义如下:

    public static class FilterProviders
        {
            static FilterProviders()
            {
                Providers = new FilterProviderCollection();
                Providers.Add(GlobalFilters.Filters);
                Providers.Add(new FilterAttributeFilterProvider());
                Providers.Add(new ControllerInstanceFilterProvider());
            }
    
            public static FilterProviderCollection Providers { get; private set; }
        }

     从中我们可以看到系统定义了三个FilterProvider,它们都实现了IFilterProvider接口,该接口定义如下:

    public interface IFilterProvider
        {
            IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor);
        }

     现在来看看这几个Provider:

        a. GlobalFilters.Filters

       这个故名思义是收集全局范围运行的Filter,代码如下: 

    public static class GlobalFilters
        {
            static GlobalFilters()
            {
                Filters = new GlobalFilterCollection();
            }
    
            public static GlobalFilterCollection Filters { get; private set; }
        }

      比如通常的项目模板在App_Start的FilterConfig中有如下代码,添加全局出错处理

    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
            {
                filters.Add(new HandleErrorAttribute());
            }

      b. FilterAttributeFilterProvider

        该类型是帮助收集应用在Controller和Action上的Filter,代码如下:

     1 public class FilterAttributeFilterProvider : IFilterProvider
     2     {
     3         private readonly bool _cacheAttributeInstances;
     4 
     5         public FilterAttributeFilterProvider()
     6             : this(true)
     7         {
     8         }
     9 
    10         public FilterAttributeFilterProvider(bool cacheAttributeInstances)
    11         {
    12             _cacheAttributeInstances = cacheAttributeInstances;
    13         }
    14 
    15         protected virtual IEnumerable<FilterAttribute> GetActionAttributes(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
    16         {
    17             return actionDescriptor.GetFilterAttributes(_cacheAttributeInstances);
    18         }
    19 
    20         protected virtual IEnumerable<FilterAttribute> GetControllerAttributes(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
    21         {
    22             return actionDescriptor.ControllerDescriptor.GetFilterAttributes(_cacheAttributeInstances);
    23         }
    24 
    25         public virtual IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
    26         {
    27             // Results are low in number in the common case so use yield return to avoid creating intermediate collections or nested enumerables
    28             if (controllerContext.Controller != null)
    29             {
    30                 foreach (FilterAttribute attr in GetControllerAttributes(controllerContext, actionDescriptor))
    31                 {
    32                     yield return new Filter(attr, FilterScope.Controller, order: null);
    33                 }
    34                 foreach (FilterAttribute attr in GetActionAttributes(controllerContext, actionDescriptor))
    35                 {
    36                     yield return new Filter(attr, FilterScope.Action, order: null);
    37                 }
    38             }             
    39         }
    40     }
    View Code

      c. ControllerInstanceFilterProvider

         controller本身也实现了一些Filter接口,通过该Provider加入,代码如下:

     1 public class ControllerInstanceFilterProvider : IFilterProvider
     2     {
     3         public IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
     4         {
     5             if (controllerContext.Controller != null)
     6             {
     7                 // Use FilterScope.First and Order of Int32.MinValue to ensure controller instance methods always run first
     8                 yield return new Filter(controllerContext.Controller, FilterScope.First, Int32.MinValue);
     9             }
    10         }
    11     }
    View Code

      接下来看一看FilterProviderCollection的GetFilters实现:

     public IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
            {
                //省略检查代码
                IFilterProvider[] providers = CombinedItems;
                List<Filter> filters = new List<Filter>();
                for (int i = 0; i < providers.Length; i++)
                {
                    IFilterProvider provider = providers[i];
                    foreach (Filter filter in provider.GetFilters(controllerContext, actionDescriptor))
                    {
                        filters.Add(filter);
                    }
                }
    
                filters.Sort(_filterComparer);
    
                if (filters.Count > 1)
                {
                    RemoveDuplicates(filters);
                }
                return filters;
            }

       从中我们可以看到,主要分为三步:

       1. 通过FilterProviders 把Filter收集到一个Filter列表

     2. 对列表进行排序,排序规则是根据Order和Scope

     3. 列表去重

       FilterComparer是Filter排序比较器,代码如下, 从中我们可以看到Order 和 Scope是怎么影响排序顺序

     1 private class FilterComparer : IComparer<Filter>
     2         {
     3             public int Compare(Filter x, Filter y)
     4             {
     5                 // Nulls always have to be less than non-nulls
     6                 if (x == null && y == null)
     7                 {
     8                     return 0;
     9                 }
    10                 if (x == null)
    11                 {
    12                     return -1;
    13                 }
    14                 if (y == null)
    15                 {
    16                     return 1;
    17                 }
    18 
    19                 // Sort first by order...
    20 
    21                 if (x.Order < y.Order)
    22                 {
    23                     return -1;
    24                 }
    25                 if (x.Order > y.Order)
    26                 {
    27                     return 1;
    28                 }
    29 
    30                 // ...then by scope
    31 
    32                 if (x.Scope < y.Scope)
    33                 {
    34                     return -1;
    35                 }
    36                 if (x.Scope > y.Scope)
    37                 {
    38                     return 1;
    39                 }
    40 
    41                 return 0;
    42             }
    43         }
    View Code

      最后返回列表传递给FilterInfo类型,FilterInfo内部处理见上面.

  • 相关阅读:
    已知二叉树的前序遍历、中序遍历,求后序遍历
    排序算法
    应用层
    运输层
    mysql分页查询
    mysql 性能分析及explain用法
    数据库SQL优化
    MATLAB GUI设计(1)
    路径选择
    Python itchat库(1)
  • 原文地址:https://www.cnblogs.com/jjyjjyjjy/p/3632626.html
Copyright © 2011-2022 走看看