过滤器(二)
好吧我们继续上一篇来挖掘。基本上明白了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,中注册的其他两个对象是不是也是过滤器。等等。
革命尚未成功,研究需要继续。