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