zoukankan      html  css  js  c++  java
  • 过滤器(二)

             好吧我们继续上一篇来挖掘。基本上明白了Action过滤器其实就应该是利用AOP的思想,在Action执行中调用了我们的过滤器方法的。就跟我们预想你一直一致。

             过滤器是实现了,也调用了,但是这个东东是从何而来,从之前看到的代码我们知道,其实也就是filter调用了我们自定义实现的过滤器,而他是怎么找到的呢。(之前看到override,就联想到抽象类,虚方法,可是看看貌似不是那么简单。)

             internal static ActionExecutedContext InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func<ActionExecutedContext> continuation)
    
            {
    
                filter.OnActionExecuting(preContext);
    
                //此处省略N行代码
    
                
    
                return postContext;
    
            }

             那么来看filter参数的来源,往回看代码我们会找到在InvokeAction方法中有这么两个关键的地方(我们只以ActionFilter为例)

             public virtual bool InvokeAction(ControllerContext controllerContext, string actionName)

           

            FilterInfo filterInfo = GetFilters(controllerContext, actionDescriptor);

             InvokeActionMethodWithFilters(controllerContext, filterInfo.ActionFilters, actionDescriptor, parameters);

             那来看下,FilterInfo的定义,大概就能猜到,FilterInfo中存储的应该是我们的所有过滤器了吧。

             貌似应该就是IActionFilter,IAuthorizationFilter,IExceptionFilter,IResultFilter,这几个就是这些过滤器需要实现的接口。从名称就应该能看出来其功能,Action过滤器,权限过滤器,异常过滤器,结果过滤器。

        public class FilterInfo
    
        {
    
            private List<IActionFilter> _actionFilters = new List<IActionFilter>();
    
            private List<IAuthorizationFilter> _authorizationFilters = new List<IAuthorizationFilter>();
    
            private List<IExceptionFilter> _exceptionFilters = new List<IExceptionFilter>();
    
            private List<IResultFilter> _resultFilters = new List<IResultFilter>();
    
     
    
            public FilterInfo()
    
            {
    
            }
    
     
    
            public FilterInfo(IEnumerable<Filter> filters)
    
            {
    
                // evaluate the 'filters' enumerable only once since the operation can be quite expensive
    
                var filterInstances = filters.Select(f => f.Instance).ToList();
    
     
    
                _actionFilters.AddRange(filterInstances.OfType<IActionFilter>());
    
                _authorizationFilters.AddRange(filterInstances.OfType<IAuthorizationFilter>());
    
                _exceptionFilters.AddRange(filterInstances.OfType<IExceptionFilter>());
    
                _resultFilters.AddRange(filterInstances.OfType<IResultFilter>());
    
            }
    
     
    
            public IList<IActionFilter> ActionFilters
    
            {
    
                get { return _actionFilters; }
    
            }
    
     
    
            public IList<IAuthorizationFilter> AuthorizationFilters
    
            {
    
                get { return _authorizationFilters; }
    
            }
    
     
    
            public IList<IExceptionFilter> ExceptionFilters
    
            {
    
                get { return _exceptionFilters; }
    
            }
    
     
    
            public IList<IResultFilter> ResultFilters
    
            {
    
                get { return _resultFilters; }
    
            }
    
        }
    

                    看完FilterInfo,我们继续往下找Filter从何而来。也就是GetFilters方法,哎呦我去,这个写法还挺复杂的,没事慢慢看

             _getFiltersThunk 是Func<ControllerContext, ActionDescriptor, IEnumerable<Filter>>个类型的委托,两个参数一个

    ControllerContext,一个ActionDescriptor,返回IEnumerable<Filter>。嗯,可以看看Filter,从名称上看可能会有关系,先记着吧

    那么我们就从FilterProviders.Providers.GetFilters找吧。

     protected virtual FilterInfo GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
    
            {
    
                return new FilterInfo(_getFiltersThunk(controllerContext, actionDescriptor));
    
            }
    
     
    
             private Func<ControllerContext, ActionDescriptor, IEnumerable<Filter>> _getFiltersThunk =          FilterProviders.Providers.GetFilters;
    
     
    
             public class Filter
    
        {
    
            public const int DefaultOrder = -1;
    
     
    
            public Filter(object instance, FilterScope scope, int? order)
    
            {
    
                if (instance == null)
    
                {
    
                    throw new ArgumentNullException("instance");
    
                }
    
     
    
                if (order == null)
    
                {
    
                    IMvcFilter mvcFilter = instance as IMvcFilter;
    
                    if (mvcFilter != null)
    
                    {
    
                        order = mvcFilter.Order;
    
                    }
    
                }
    
     
    
                Instance = instance;
    
                Order = order ?? DefaultOrder;
    
                Scope = scope;
    
            }
    
     
    
            public object Instance { get; protected set; }
    
     
    
            public int Order { get; protected set; }
    
     
    
            public FilterScope Scope { get; protected set; }
    
        }
    

                先来看看FilterProviders东西吧。静态类,其实就维护了一个FilterProviderCollection 个东东,也就是Providers属性。看其定义,其实就是一个IFilterProvider的集合么。看看他的GetFilters方法是如何实现的吧。还记得我们过滤器是如何注册的么,之前好像忘了提这个了,这里补上,在Global.asax文件中有这么句话

    FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); 注册全局过滤器,看代码,嗯,就那么个意思。         

    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    
            {
    
                filters.Add(new HandleErrorAttribute());
    
                // Custom global action filters...
    
                filters.Add(new UserLoginInfoAttribute());
    
            }
    
     
    
             public static class GlobalFilters
    
        {
    
            static GlobalFilters()
    
            {
    
                Filters = new GlobalFilterCollection();
    
            }
    
     
    
            public static GlobalFilterCollection Filters { get; private set; }
    
        }
    
     
    
             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; }
    
        }
    

                这时候大概能看出点眉目了吧,至少全局注册的过滤器,这里基本上能接上了。然后继续往下看。FilterProviderCollection 的GetFilters方法其实是调用了IFilterProvider的GetFilters

             public class FilterProviderCollection : Collection<IFilterProvider>
    
        {
    
            private static FilterComparer _filterComparer = new FilterComparer();
    
            private IResolver<IEnumerable<IFilterProvider>> _serviceResolver;
    
     
    
            public FilterProviderCollection()
    
            {
    
                _serviceResolver = new MultiServiceResolver<IFilterProvider>(() => Items);
    
            }
    
     
    
            public FilterProviderCollection(IList<IFilterProvider> providers)
    
                : base(providers)
    
            {
    
                _serviceResolver = new MultiServiceResolver<IFilterProvider>(() => Items);
    
            }
    
     
    
            internal FilterProviderCollection(IResolver<IEnumerable<IFilterProvider>> serviceResolver, params IFilterProvider[] providers)
    
                : base(providers)
    
            {
    
                _serviceResolver = serviceResolver ?? new MultiServiceResolver<IFilterProvider>(() => Items);
    
            }
    
     
    
            private IEnumerable<IFilterProvider> CombinedItems
    
            {
    
                get { return _serviceResolver.Current; }
    
            }
    
     
    
            private static bool AllowMultiple(object filterInstance)
    
            {
    
                IMvcFilter mvcFilter = filterInstance as IMvcFilter;
    
                if (mvcFilter == null)
    
                {
    
                    return true;
    
                }
    
     
    
                return mvcFilter.AllowMultiple;
    
            }
    
     
    
            public IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
    
            {
    
                if (controllerContext == null)
    
                {
    
                    throw new ArgumentNullException("controllerContext");
    
                }
    
                if (actionDescriptor == null)
    
                {
    
                    throw new ArgumentNullException("actionDescriptor");
    
                }
    
     
    
                IEnumerable<Filter> combinedFilters =
    
                    CombinedItems.SelectMany(fp => fp.GetFilters(controllerContext, actionDescriptor))
    
                        .OrderBy(filter => filter, _filterComparer);
    
     
    
                // Remove duplicates from the back forward
    
                return RemoveDuplicates(combinedFilters.Reverse()).Reverse();
    
            }
    
     
    
            private IEnumerable<Filter> RemoveDuplicates(IEnumerable<Filter> filters)
    
            {
    
                HashSet<Type> visitedTypes = new HashSet<Type>();
    
     
    
                foreach (Filter filter in filters)
    
                {
    
                    object filterInstance = filter.Instance;
    
                    Type filterInstanceType = filterInstance.GetType();
    
     
    
                    if (!visitedTypes.Contains(filterInstanceType) || AllowMultiple(filterInstance))
    
                    {
    
                        yield return filter;
    
                        visitedTypes.Add(filterInstanceType);
    
                    }
    
                }
    
            }
    
     
    
            private class FilterComparer : IComparer<Filter>
    
            {
    
                public int Compare(Filter x, Filter y)
    
                {
    
                    // Nulls always have to be less than non-nulls
    
                    if (x == null && y == null)
    
                    {
    
                        return 0;
    
                    }
    
                    if (x == null)
    
                    {
    
                        return -1;
    
                    }
    
                    if (y == null)
    
                    {
    
                        return 1;
    
                    }
    
     
    
                    // Sort first by order...
    
     
    
                    if (x.Order < y.Order)
    
                    {
    
                        return -1;
    
                    }
    
                    if (x.Order > y.Order)
    
                    {
    
                        return 1;
    
                    }
    
     
    
                    // ...then by scope
    
     
    
                    if (x.Scope < y.Scope)
    
                    {
    
                        return -1;
    
                    }
    
                    if (x.Scope > y.Scope)
    
                    {
    
                        return 1;
    
                    }
    
     
    
                    return 0;
    
                }
    
            }
    
        }
    
            
    
      /// <summary>
    
      /// 提供用于查找筛选器的接口。
    
      /// </summary>
    
      public interface IFilterProvider
    
      {
    
        /// <summary>
    
        /// 返回一个包含服务定位器中的所有 <see cref="T:System.Web.Mvc.IFilterProvider"/> 实例的枚举器。
    
        /// </summary>
    
        ///
    
        /// <returns>
    
        /// 包含服务定位器中的所有 <see cref="T:System.Web.Mvc.IFilterProvider"/> 实例的枚举器。
    
        /// </returns>
    
        /// <param name="controllerContext">控制器上下文。</param><param name="actionDescriptor">操作描述符。</param>
    
        IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor);
    
      }
    

      

             好吧,脑子已经基本上乱的够呛了,一起捋一捋,ControllerActionInvoker提供了Action的执行,那么执行方法之中提供了执行过滤器的地方,而且在执行过滤器之前,通过FilterProviders,(一个静态类,初始化注册了三种东西。其中包括GlobalFilters.Filters,FilterAttributeFilterProvider,ControllerInstanceFilterProvider,我们只关注GlobalFilters.Filters)初始化注册了全局过滤器, 然后看我们的GlobalFilters。(也是一个静态了,维护了全局的过滤器集合),在Global.asax中我们已经注册了我们需要的过滤器,好吧这么就贯通下来了。从全局过滤器的注册,获取,执行。我们都已经看到了。

             可以看到,代码中应用了大量的xx Provider的方式提供一些东西,其实就是管理一个集合对象的静态类,静态构造中会进行一些初始化工作,然后维护了一个对应对象的集合。该集合提供了一些集合的操作和枚举器的实现。貌似是种设计模式吧,鄙人才疏学浅,还需要查查,哪位大神指导可否指点一二。

             从我们的分析中,我们只看了过滤器中的一部分代码而已,所以肯定的其中还有很多我们没有看到。不过基本已经明白了全局过滤器的实现了,不过这篇我们也能学到不少东东了,不过问题也更多了。比如看Controller的定义貌似也是个过滤器(实现了过滤器接口),怎么用呢。我们只大致研究了下Action过滤器而已,其他的几个过滤器是不是也要搞几个Demo看看(猜测实现和思路应该是一样一样滴),FilterProviders,中注册的其他两个对象是不是也是过滤器。等等。

             革命尚未成功,研究需要继续。

  • 相关阅读:
    使用 yo 命令行向导给 SAP UI5 应用添加一个新的视图
    SAP Fiori Elements 应用的 manifest.json 文件运行时如何被解析的
    SAP UI5 标准应用的多语言支持
    微软 Excel 365 里如何设置下拉菜单和自动高亮成指定颜色
    SAP Fiori Elements 应用里的 Title 显示的内容是从哪里来的
    本地开发好的 SAP Fiori Elements 应用,如何部署到 ABAP 服务器上?
    如何在 Cypress 测试代码中屏蔽(Suppress)来自应用代码报出的错误消息
    教你一招:让集群慢节点无处可藏
    应用架构步入“无服务器”时代 Serverless技术迎来新发展
    MySQL数据库事务隔离性的实现
  • 原文地址:https://www.cnblogs.com/superCow/p/3803056.html
Copyright © 2011-2022 走看看