简说MVC Filter
Filter与FilterProvider之间的关系
根据用途和执行时机的不同,MVC主要分为以下5种类型的过虑器:AuthenticationFilter、AuthorizationFilter、ActionFilter、ExceptionFilter、ResultFilter。下面我们来看一个IFilter接口,如下所示:
public class Filter
{
public const int DefaultOrder = -; public Filter(object instance, FilterScope scope, int? order)
{
//省略
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; }
} public enum FilterScope
{
First = ,
Global = ,
Controller = ,
Action = ,
Last = ,
}
一个Filter对象就是对一个过滤器的封装,它将过滤器对象封装在Instance属性中。表示排序的Order属性,默认为-1,值越小越优先。还有一个表示范围的Scope属性,它是一个枚举类型。其中Global、Controller、Action分别表示应用到整个应用范围内、某个Controller上、某个Action上,另两个First、Last表明是应用的第一个还是最后一个。如果前面的Order属性的值一样大,那么相同的Order的Filter则会按照Scope属性值越小越优先。
所有的Filter均是通过FilterProvider来提供的,该接口的定义如下所示:
public interface IFilterProvider
{
IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor);
}
该接口只定义了一个GetFilters方法,用于获取某个Action方法上所有的Filter。它具有两个参数ControllerContext表示当前的Controller的上下文,ActionDescriptor描述目标Action方法。
用于提供Filter的FilterProvider是通过静态类型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; }
}
从上我们看到MVC提供了三种原生的FilterProvider,它们分别是:GlobalFilters.Filters用于提供全局、FilterAttributeFilterProvider用于提供Controller类和Action方法上、ControllerInstanceFilterProvider用于提供Controller这个别特的过滤器。下面来看FilterProvider是如何提供Filter的。
1、FilterAttributeFilterProvider
我们通常是将过滤器定义成特性的方式标注到某个Controller或Action上。这样的过滤器特性一般以FilterAttribute作为基类。它实现了IMvcFilter接口,IMvcFilter只有两个只读属性成员Order和AllowMultiple。在上面的Filter类中我们看到如果实例可以转换为IMvcFilter接口,那么则将IMvcFilter的Order值赋给Filter的Order属性。我们在某个Action方法或Controller上标记某个特性时,可以在上面指定Order值,如[Authorize(Order =3)]。如下所示:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)]
public abstract class FilterAttribute : Attribute, IMvcFilter
{
private static readonly ConcurrentDictionary<Type, bool> _multiuseAttributeCache = new ConcurrentDictionary<Type, bool>();
private int _order = Filter.DefaultOrder; public bool AllowMultiple
{
get { return AllowsMultiple(GetType()); }
} public int Order
{
get { return _order; }
set
{
if (value < Filter.DefaultOrder)
{
throw new ArgumentOutOfRangeException("value", MvcResources.FilterAttribute_OrderOutOfRange);
}
_order = value;
}
} private static bool AllowsMultiple(Type attributeType)
{
return _multiuseAttributeCache.GetOrAdd(
attributeType,
type => type.GetCustomAttributes(typeof(AttributeUsageAttribute), true)
.Cast<AttributeUsageAttribute>()
.First()
.AllowMultiple);
}
} public interface IMvcFilter
{
bool AllowMultiple { get; }
int Order { get; }
}
从应用在FilterAttribute的AttributeUsageAttribute特性上我们可以看到此特性可以应用到类和方法上,AllowMultiple默认为false,不允许多个。
获取Controller类和Action方法上的特性是通过FilterAttributeFilterProvider来提供的。如下所示:
public class FilterAttributeFilterProvider : IFilterProvider
{
private readonly bool _cacheAttributeInstances; public FilterAttributeFilterProvider()
: this(true)
{
} public FilterAttributeFilterProvider(bool cacheAttributeInstances)
{
_cacheAttributeInstances = cacheAttributeInstances;
} protected virtual IEnumerable<FilterAttribute> GetActionAttributes(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
{
return actionDescriptor.GetFilterAttributes(_cacheAttributeInstances);
} protected virtual IEnumerable<FilterAttribute> GetControllerAttributes(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
{
return actionDescriptor.ControllerDescriptor.GetFilterAttributes(_cacheAttributeInstances);
} public virtual IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
{
// Results are low in number in the common case so use yield return to avoid creating intermediate collections or nested enumerables
if (controllerContext.Controller != null)
{
foreach (FilterAttribute attr in GetControllerAttributes(controllerContext, actionDescriptor))
{
yield return new Filter(attr, FilterScope.Controller, order: null);
}
foreach (FilterAttribute attr in GetActionAttributes(controllerContext, actionDescriptor))
{
yield return new Filter(attr, FilterScope.Action, order: null);
}
}
}
}
从上面的静态类FilterProviders中,我们可以看到MVC默认注册的是FilterAttributeFilterProvider的无参构造函数,然后它传一个true调用有参构造函数,该_cacheAttributeInstances字段表示是否缓存获取到的Filter。因为是通过反射获取Controller和Action上的Filter,所以MVC默认缓存获取到的Filter,提高性能。
该类实现的GetFilters方法,它会先后调用GetControllerAttributes方法和GetActionAttributes方法,分别获取Cotroller和Action上Filter。分别用于描述 Controller和Action的ControllerDescriptor和ActionDescriptor类实现了ICustomAttributeProvider接口。我们可以调用相应的方法获取应用在对应的Controller类型或Action方法上包括FilterAttribute在内的所有特性。如下所示:
public abstract class ControllerDescriptor : ICustomAttributeProvider, IUniquelyIdentifiable
{
public virtual object[] GetCustomAttributes(Type attributeType, bool inherit)
{
if (attributeType == null)
{
throw new ArgumentNullException("attributeType");
} return (object[])Array.CreateInstance(attributeType, );
} public virtual IEnumerable<FilterAttribute> GetFilterAttributes(bool useCache)
{
return GetCustomAttributes(typeof(FilterAttribute), inherit: true).Cast<FilterAttribute>();
}
} public abstract class ActionDescriptor : ICustomAttributeProvider, IUniquelyIdentifiable
{
public virtual object[] GetCustomAttributes(Type attributeType, bool inherit)
{
if (attributeType == null)
{
throw new ArgumentNullException("attributeType");
} return (object[])Array.CreateInstance(attributeType, );
} public virtual IEnumerable<FilterAttribute> GetFilterAttributes(bool useCache)
{
return GetCustomAttributes(typeof(FilterAttribute), inherit: true).Cast<FilterAttribute>();
}
}
2、ControllerInstanceFilterProvider
Controller本身就是一个过滤器,如下所示:
public abstract class Controller : ControllerBase, IActionFilter, IAuthenticationFilter, IAuthorizationFilter, IDisposable, IExceptionFilter, IResultFilter, IAsyncController, IAsyncManagerContainer
{
//省略
}
对于Controller这个特殊的过滤器,其对应的FilterProvider类型,如下所示:
public class ControllerInstanceFilterProvider : IFilterProvider
{
public IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
{
if (controllerContext.Controller != null)
{
// Use FilterScope.First and Order of Int32.MinValue to ensure controller instance methods always run first
yield return new Filter(controllerContext.Controller, FilterScope.First, Int32.MinValue);
}
}
}
它的GetFilter方法跟据ControllerContext获取对应的Controller对象,并以此创建对应的Filter。
3、GlobalFilters.Filters
全局过滤器,它不是显示的应用于某个Controller、某个Action上,而是默认应用到整个程序的所有Controller类型的Action方法上。如下所示:
public static class GlobalFilters
{
static GlobalFilters()
{
Filters = new GlobalFilterCollection();
} public static GlobalFilterCollection Filters { get; private set; }
}
GlobalFilters就只有一个属性GlobalFilterCollection,GlobalFilterCollection它是一个元素类型为Filter的集合,它显示地实现了IFilterProvider接口的GetFilters方法,返回的就是它自己,如下所示:
public sealed class GlobalFilterCollection : IEnumerable<Filter>, IFilterProvider
{
private List<Filter> _filters = new List<Filter>(); public void Add(object filter)
{
AddInternal(filter, order: null);
} public void Add(object filter, int order)
{
AddInternal(filter, order);
} private void AddInternal(object filter, int? order)
{
ValidateFilterInstance(filter);
_filters.Add(new Filter(filter, FilterScope.Global, order));
} IEnumerable<Filter> IFilterProvider.GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
{
return this;
}
//省略
}
到目前为止,MVC默认提供的3种原生的FilterProvider以及各自采用的Filter提供机制介绍完毕。MVC的5种过滤器最终被封装成相应的Filter对象,但是它们的执行时机和方式是不同的,所以在执行之前需要根据被封装的过滤器类型对所有的Filter进行分组。就是当ControllerActionInvoker被调用时,它会利用静态类型FilterProviders得到所有注册的IFilterProvider类型,然后利用当前的ControllerContext和ActionDescriptor对象得到Filter,然后根据其Instance属性表示的过滤器类型,将它分组,最终得到一个具有如下所示FilterInfo类型的对象。
public class FilterInfo
{
public IList<IActionFilter> ActionFilters { get; } public IList<IAuthenticationFilter> AuthenticationFilters { get; } public IList<IAuthorizationFilter> AuthorizationFilters { get; } public IList<IExceptionFilter> ExceptionFilters { get; } public IList<IResultFilter> ResultFilters { get; }
}
简说MVC Filter的更多相关文章
- MVC Filter 实现方式和作用范围控制
Asp.Net MVC Filter 实现方式和作用范围控制 MVC中的Filte 简单又优雅的实现了AOP ,在日志,权限,缓存和异常处理等方面用的比较多.但本文不是讨论Filter这些功能点,而是 ...
- 学习之-ASP.NET MVC Filter
MVC Filter 是典型的AOP应用,对MVC框架处理客户端请求注入额外的一些逻辑,如日志记录.缓存处理.异常处理和权限验证,性能检测(横切关注点),而这些逻辑通常与主要业务无关,被独立分开作为公 ...
- .NET MVC Filter异常处理
MVC程序中自带的HandleErrorAttribute,来处理异常,不在显示黄页.前提是在web.config 中 system.web中关闭customerError选项. 但是很多情况下调试异 ...
- IoC容器Autofac(5) - Autofac在Asp.net MVC Filter中的应用
Autofac结合EF在MVC中的使用,上一篇IoC容器Autofac(4) - Autofact + Asp.net MVC + EF Code First(附源码)已经介绍了.但是只是MVC中Co ...
- Asp.Net MVC Filter 实现方式和作用范围控制
MVC中的Filte 简单又优雅的实现了AOP ,在日志,权限,缓存和异常处理等方面用的比较多.但本文不是讨论Filter这些功能点,而是总结Filter实现的方式.说实现也不太准确,也就是它的呈现方 ...
- MVC Filter自定义验证(拦截)
namespace QS.Web.Extensions { /// <summary> /// 验证session.权限 状态 /// </summary> [Attribut ...
- ASP.NET MVC Filter的思考
思考了一下AOP的具体实现,后来想到ASP.NET MVC过滤器其实就是AOP的一种,于是从Filter下手研究AOP. 暂时先考虑AuthorizationFilter,ActionFilter,R ...
- MVC Filter
一.Filter在MVC生命周期中的位置 1.IIS中传递请求到程序2.MVC根据Routing来选择由哪个Controller/Action来处理3.Controller调用Model(业务逻辑)来 ...
- Asp.net Mvc (Filter及其执行顺序)
应用于Action的Filter 在Asp.netMvc中当你有以下及类似以下需求时你可以使用Filter功能判断登录与否或用户权限,决策输出缓存,防盗链,防蜘蛛,本地化设置,实现动态Actionfi ...
随机推荐
- vue构造器以及实例属性
一.构造器 1.vue.js就是一个构造器,通过构造器Vue来实例化一个对象:例如:var vm = new Vue({}); 2.实例化Vue时,需要传入一个参数(选项对象): 3.参数:选项对象可 ...
- Hibernate核心开发接口_SessionFactory详解
SessionFactory: a) 用来产生和管理Session b)通常情况下每个应用只需要一个SessionFactory c)除非要访问多个数据库的情况 d) 关注两个方法即: openS ...
- Javac源码解读-书目录
1.Javac编译器 (1)Javac编译器介绍(主要介绍如何从java源代码到class的一个转换过程) (2)Javac的源码(说明其中哪个功能由哪个主要的类来完成) (3)Javac支持的命令及 ...
- ActiveMQ:Exception occurred while processing this request, check the log for more information!
出现上面错误的原因有以下两种 1 jdk的版本和activemq的版本不符 安装完ActiveMQ之后,通过http://IP:8161登陆到控制台. 通过测试代码给服务端发送队列消息,在控制台点击q ...
- Linux 进程以及多线程的支持
1.最初内核并没有实现对多线程的支持,2.6之后开始以轻量级进程的方式对多线程进行支持(轻量级线程组). a.在2.6 之前,如果需要实现多线程,只能在用户态下实现,用户程序自己控制线程的切换, 实际 ...
- struts2 servlet之间通信
Servlet之间通信的方式有两大类,每个类有三种不同的方法 1.request 2.session 3.application 不实现ServletContextAware,SessionAware ...
- Ubuntu系统Apache Maven安装
操作系统:Linux x64 / Ubuntu 14.04 Apache Maven版本:3.3.9 建议预先搭建Java开发环境:详见上一篇<Linux Ubuntu系统下Java开发环境搭建 ...
- C#调用SQLite报错:无法加载 DLL“SQLite.Interop.dll”: 找不到指定的模块
C#调用SQLite数据库,有些情况下会报以下这个错误: 无法加载 DLL“SQLite.Interop.dll”: 找不到指定的模块 实际上程序目录中是存在SQLite.Interop.dll这个文 ...
- CC2530zigbee技术-简介协议栈
前言 说实话,我喜欢自己的原创,虽然我写得可能简单了,但我觉得自己在写博客的路途上,一点一点地积累知识,我也借鉴别人的东西,特别是在写这篇文章时所使用的是markdownpad2写的,原来我根本就不知 ...
- PHP命名规则
参考: http://nowhisky.diandian.com/post/2012-08-12/40033898638 就一般约定而言,类.函数和变量的名字应该是能够让代码阅读者能够容易地知道这些代 ...