- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章详解ASP.NET MVC的筛选器由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
在ActionInvoker对Action的执行过程中,除了通过利用ActionDescriptor对Action方法的执行,以及之前进行的Model绑定与验证之外,还具有一个重要的工作,那就是对相关筛选器(Filter)的执行。ASP.NET MVC的筛选器是一种基于AOP(面向方面编程)的设计,我们将一些非业务的逻辑实现在相应的筛选器中,然后以一种横切(Crosscutting)的方式应用到对应的Action方法。当Action方法执行前后,这些筛选器会自动执行。ASP.NET MVC提供了四种类型的筛选器(AuthorizationFilter、ActionFilter、ResultFilter和ExceptionFilter),它们对应着相应的筛选器接口(IAuthorizationFilter、IActionFilter、IResultFilter和IExceptionFilter)。[本文已经同步到《How ASP.NET MVC Works?》中] 。
目录 。
1、Filter 。
2、FilterProvider 。
3、FilterAttribute与FilterAttributeFilterProvider 。
4、Controller与ControllerInstanceFilterProvider 。
5、GlobalFilterCollection 。
6、实例演示:验证Filter的提供机制和执行顺序 。
1、Filter 。
虽然ASP.NET MVC提供的四种类型的筛选器具有各自实现的接口,但是对于筛选器的提供体系来说所有的筛选器都通过具有如下定义的Filter类型表示。Filter的核心是Instance属性,因为它代表真正实施筛选功能的对象,该对象实现了一个或者多个基于上述四种筛选器类型的接口.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
public
class
Filter
{
public
const
int
DefaultOrder = -1;
public
Filter(
object
instance, FilterScope scope,
int
? order);
public
object
Instance {
get
;
protected
set
; }
public
int
Order {
get
;
protected
set
; }
public
FilterScope Scope {
get
;
protected
set
; }
}
public
enum
FilterScope
{
Action = 30,
Controller = 20,
First = 0,
Global = 10,
Last = 100
}
|
注:由于System.Web.Mvc.Filter和实现了IAuthorizationFilter、IActionFilter、IResultFilter和IExceptionFilter的类型均可以被称为“筛选器”,为了不至于造成混淆,在没有做明确说明的情况下,我们使用英文“Filter”和中文“筛选器”分别来表示它们.
Filter的Order和Scope属性最终决定了筛选器的执行顺序。Order属性对应数值越小,执行的优先级越高,该属性的默认值为-1(对应着Filter中定义的常量DefaultOrder)。如果两个Filter具有相同的Order属性值,那么Scope属性最终决定哪个被优先执行。Filter的Scope属性类型是一个类型为FilterScope的枚举。该枚举表示应用Filter的范围,Action和Controller代表Action方法和Controller类级别;First和Last意味着希望被作为第一个和最后一个Filter来执行;Global代表一个全局的Filter.
通过上面的代码片断我们可以看到FilterScope的5个枚举选项均被设置了一个值,这个值决定了Filter的执行顺序,具有更小的枚举值会被优先执行。从FilterScope的定义可以得到这样的结论:对于具有相同Order属性值的多个Filter,应用在Controller上的Filter比应用在Action方法上的Filter具有更高的执行优先级,而一个全局的Filter的执行优先级又高于基于Action的Filter.
2、FilterProvider 。
Filter的提供机制与之前我们介绍的基于ModelBinder和ModelValidator的提供机制比较类似,均是通过相应的Provider来提供的。提供筛选器的FilterProvider实现了接口IFilterProvider,如下面的代码片断所示,该接口定义了唯一的方法GetFilters根据指定的Controller上下文和用于描述目标Action的ActionDescriptor对象获取一个Filter对象集合.
1
2
3
4
|
public
interface
IFilterProvider
{
IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor);
}
|
我们可以通过静态类型FilterProviders注册或者获取当前应用使用的FilterProvider。如下面的代码片断所示,FilterProviders具有一个类型为FilterProviderCollection的只读属性Providers,表示基于整个Web应用范围内被使用的FilterProvider列表。FilterProviderCollection是元素类型为IFilterProvider的集合,GetFilters方法用于或者该集合中所有FilterProvider对象提供的Filter对象.
1
2
3
4
5
6
7
8
9
|
public
static
class
FilterProviders
{
public
static
FilterProviderCollection Providers {
get
; }
}
public
class
FilterProviderCollection : Collection<IFilterProvider>
{
//其他成员
public
IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor);
}
|
ASP.NET MVC提供了三种原生的FilterProvider,分别是FilterAttributeFilterProvider、ControllerInstanceFilterProvider和GlobalFilterCollection,接下来我们对它们进行单独介绍.
3、FilterAttribute与FilterAttributeFilterProvider 。
我们通常将筛选器定义成特性以声明的方式应用到Controller类型或者Action方法上,而抽象类型FilterAttribute是所有筛选器的基类。如下面的代码片断所示,FilterAttribute特性实现了IMvcFilter接口,该接口定义了Order和AllowMultiple两个只读属性,分别用于控制筛选器的执行顺序以及多个同类的筛选器能够同时应用到同一个目标元素(类或者方法).
1
2
3
4
5
6
7
8
9
10
11
12
13
|
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited=
true
, AllowMultiple=
false
)]
public
abstract
class
FilterAttribute : Attribute, IMvcFilter
{
protected
FilterAttribute();
public
bool
AllowMultiple {
get
; }
public
int
Order {
get
;
set
; }
}
public
interface
IMvcFilter
{
bool
AllowMultiple {
get
; }
int
Order {
get
; }
}
|
从应用在FilterAttribute上的AttributeUsageAttribute的定义可以看出该特性可以应用在类型和方法上,这意味着筛选器一般都可以应用在Controller类型和Action方法上。只读属性AllowMultiple实际上返回的是AttributeUsageAttribute的同名属性,通过上面的定义我们可以看到默认情况下该属性值为False.
用于描述Controller和Action的ControllerDescriptor和ActionDescriptor均实现了ICustomAttributeProvider接口,我们可以直接利用它们获取应用在对应的Controller类型或者Action方法上包括FilterAttribute在内的所有特性。实际上,这两个描述类型提供了单独的方法GetFilterAttributes专门用于获取FilterAttribute特性列表。如下面的代码片断所示,该方法具有一个布尔类型的参数useCache,表示是否需要对解析出来的FilterAttribute特性进行缓存以缓解频繁的反射操作对性能造成的影响.
1
2
3
4
5
6
7
8
9
10
|
public
abstract
class
ControllerDescriptor : ICustomAttributeProvider, IUniquelyIdentifiable
{
//其他成员
public
virtual
IEnumerable<FilterAttribute> GetFilterAttributes(
bool
useCache);
}
public
abstract
class
ActionDescriptor : ICustomAttributeProvider, IUniquelyIdentifiable
{
//其他成员
public
virtual
IEnumerable<FilterAttribute> GetFilterAttributes(
bool
useCache);
}
|
针对FilterAttribute特性的Filter通过FilterAttributeFilterProvider对象来提供。FilterAttributeFilterProvider直接调用当前ControllerDescriptor和ActionDescriptor的GetFilterAttributes方法获取所有应用在Controller类型和当前Action方法的FilterAttribute特性,并借此创建相应的Filter对象。FilterAttributeFilterProvider构造函数的参数cacheAttributeInstances表示是否启用针对FilterAttribute的缓存,它将作为调用GetFilterAttributes方法的参数。在默认的情况下(通过调用默认无参的构造函数创建的FilterAttributeFilterProvider)会采用针对FilterAttribute的缓存.
1
2
3
4
5
6
7
8
|
public
class
FilterAttributeFilterProvider : IFilterProvider
{
public
FilterAttributeFilterProvider();
public
FilterAttributeFilterProvider(
bool
cacheAttributeInstances);
protected
virtual
IEnumerable<FilterAttribute> GetActionAttributes(ControllerContext controllerContext, ActionDescriptor actionDescriptor);
protected
virtual
IEnumerable<FilterAttribute> GetControllerAttributes(ControllerContext controllerContext, ActionDescriptor actionDescriptor);
public
virtual
IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor);
}
|
对于通过调用GetFilters得到的Filter,对应的FilterAttribute特性作为其Instance属性。Order属性来源于FilterAttribute的同名属性,而Scope属性则取决于FilterAttribute特性是应用在Controller类型上(Scope属性值为Controller)还是当前的Action方法上(Scope属性值为Action).
4、Controller与ControllerInstanceFilterProvider 。
提到ASP.NET MVC的筛选器,大部分的都只会想到通过FilterAttribute特性,实际上Controller本身(继承自抽象类Controller)就是一个筛选器。如下面的代码片断所示,抽象类Controller实现了IActionFilter、IAuthorizationFilter、IExceptionFilter和IResultFilter这四个对应着不同筛选器类型的接口.
1
2
3
4
5
6
7
8
9
|
public
abstract
class
Controller : ControllerBase,
IActionFilter,
IAuthorizationFilter,
IExceptionFilter,
IResultFilter,
...
{
//省略成员
}
|
针对Controller对象这种独特筛选器的FilterProvider类型为具有如下定义的ControllerInstanceFilterProvider。在实现的GetFilters方法中,它会根据指定的Controller上下文获取对应的Controller对象,并以此创建一个Filter(Controller对象作为Filter对象的Instance属性值)。该Filter的Scope不是Controller,而是First,而Order的值为-2147483648(Int32.MinValue),毫无疑问这样的Filter肯定第一个被执行.
1
2
3
4
|
public
class
ControllerInstanceFilterProvider : IFilterProvider
{
public
IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor);
}
|
5、GlobalFilterCollection 。
通过FilterAttribute的形式定义的筛选器需要显式地标注到目标Controller类型或者Action方法上,而在有些情况下需要一种全局的Filter。所谓全局筛选器,就是不需要显式与某个Controller或者Action进行匹配,而是默认使用到所有的Action执行过程中。用于提供这种全局Filter的FilterProvider对应的类型为具有如下定义的GlobalFilterCollection.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
public
sealed
class
GlobalFilterCollection : IEnumerable<Filter>, IEnumerable, IFilterProvider
{
public
GlobalFilterCollection();
public
void
Add(
object
filter);
public
void
Add(
object
filter,
int
order);
private
void
AddInternal(
object
filter,
int
? order);
public
void
Clear();
public
bool
Contains(
object
filter);
public
IEnumerator<Filter> GetEnumerator();
public
void
Remove(
object
filter);
IEnumerator IEnumerable.GetEnumerator();
IEnumerable<Filter> IFilterProvider.GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor);
public
int
Count {
get
; }
}
|
通过命名以及上面给出的定义可以看出GlobalFilterCollection就是一个Filter的列表而已,实现的GetFilters方法返回的就是它自己。通过GlobalFilterCollection提供的方法我们可以实现对全局Filter的添加、删除和清除操作。用于添加Filter的Add方法的参数filter不是一个Filter对象,而是一个具体筛选器(实现了相应的筛选器接口),添加的Filter对象根据该筛选器对象创建,其Scope属性被设置成Global。我们通过在Add方法指定添加Filter对象的Order属性,如果没有显示指定Order并且指定的筛选器是一个FilterAttribute特性,那么该特性的Order将会作为Filter对象的Order;否则使用-1作为Order属性值.
针对整个Web应用的全局Filter(或者说全局FilterProvider)的注册和获取可以通过静态类型GlobalFilters来实现。如下面的代码片断所示,GlobalFilters具有一个静态只读属性Filters返回一个GlobalFilterCollection对象.
1
2
3
4
|
public
static
class
GlobalFilters
{
public
static
GlobalFilterCollection Filters {
get
; }
}
|
到目前为止,我们已经介绍了ASP.NET MVC默认提供的三种FilterProvider,以及各自采用得Filter提供机制。当用于注册FilterProvider的静态类型在加载的时候,会默认创建这三种类型的对象并将其作为表示全局FilterProvider集合的Providers属性值,具体的逻辑体现在如下的代码片断中。也就是说,在默认的情况下ASP.NET MVC会采用这三种FilterProvider来提供所有的Filter对象.
1
2
3
4
5
6
7
8
9
10
11
|
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
;}
}
|
6、实例演示:验证Filter的提供机制和执行顺序 。
为了让读者对上面介绍的Filter提供机制具有一个更加深刻的映像,我们来做一个简单的实例演示。在一个通过Visual Studio的ASP.NET MVC项目模板创建的空Web项目中,我们定义了如下一个几个FilterAttribute。FilterBaseAttribute是一个实现了IActionFilter接口的抽象类型,三个具体的FilterAttribute(FooAttribute、BarAttribute和BazAttribute)是它的继承者.
1
2
3
4
5
6
7
8
9
10
11
12
13
|
public
abstract
class
FilterBaseAttribute:FilterAttribute, IActionFilter
{
public
void
OnActionExecuted(ActionExecutedContext filterContext)
{}
public
void
OnActionExecuting(ActionExecutingContext filterContext)
{}
}
public
class
FooAttribute : FilterBaseAttribute
{}
public
class
BarAttribute : FilterBaseAttribute
{}
public
class
BazAttribute : FilterBaseAttribute
{}
|
我们首先在Global.asax中通过如下的方式将BazAttribute注册为一个全局筛选器。需要注意的是定义在默认创建的Global.asax中的Application_Start方法会调用RegisterGlobalFilters方法注册一个类型为HandleErrorAttribute的ExceptionFilter,我们需要将这行代码注释.
1
2
3
4
5
6
7
8
9
10
|
public
class
MvcApplication : System.Web.HttpApplication
{
//其他成员
protected
void
Application_Start()
{
//其他操作
//RegisterGlobalFilters(GlobalFilters.Filters);
GlobalFilters.Filters.Add(
new
BazAttribute());
}
}
|
最后我们创建如下一个默认的HomeController,一个空的Action方法Data上应用了我们定义的BarAttribute特性,而HomeController类上则应用了FooAttribute特性。在默认的Action方法Index中,我们通过FilterProviders的静态属性Providers表示的全局FilterProvider列表得到针对于Action方法Data的所有Filter对象,并将它们的基本信息(类型、Order和Scope属性)呈现出来.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
[Foo]
public
class
HomeController : Controller
{
public
void
Index()
{
ReflectedControllerDescriptor controllerDescriptor =
new
ReflectedControllerDescriptor(
typeof
(HomeController));
ActionDescriptor actionDescriptor = controllerDescriptor.FindAction(ControllerContext,
"Data"
);
foreach
(var filter
in
FilterProviders.Providers.GetFilters(ControllerContext, actionDescriptor))
{
Response.Write(
string
.Format(
"{0}<br/>"
,filter.Instance));
Response.Write(
string
.Format(
" {0}: {1}<br/>"
,
"Order"
,filter.Order));
Response.Write(
string
.Format(
" {0}: {1}<br/><br/>"
,
"Scope"
,filter.Scope));
}
}
[Bar]
public
void
Data()
{ }
}
|
运行我们的程序之后会在浏览器中呈现如图7-5所示的结果。我们可以清楚地看到,不仅仅应用在自身Action方法的FilterAttribute会应用到目标Action上,应用在Controller类的FilterAttribute、全局注册的Filter以及Controller对象本身体现的Filter都回最终应用在所有的Action上面.
上图将应用于Action方法Data的4个Filter的Order和Scope属性显示出来。我们在前面提到这两个属性决定了同类筛选器执行的顺序,我们现在利用这个程序要证实这一点。为此我们需要对FilterBaseAttribute作如下的修改,在OnActionExecuting中我们将当前执行的FilterAttribute的类型的方法名呈现出来.
1
2
3
4
5
6
7
8
9
|
public
abstract
class
FilterBaseAttribute:FilterAttribute, IActionFilter
{
public
void
OnActionExecuted(ActionExecutedContext filterContext)
{}
public
void
OnActionExecuting(ActionExecutingContext filterContext)
{
filterContext.HttpContext.Response.Write(
string
.Format(
"{0}.OnActionExecuting()<br/>"
,
this
.GetType()));
}
}
|
然后我们按照相同的方式重写了HomeController的OnActionExecuting方法,将HomeController自身的类型的当前方法名称呈现出来.
1
2
3
4
5
6
7
8
9
10
11
12
|
[Foo]
public
class
HomeController : Controller
{
//其他成员
protected
override
void
OnActionExecuting(ActionExecutingContext filterContext)
{
Response.Write(
"HomeController.OnActionExecuting()<br/>"
);
}
[Bar]
public
void
Data()
{ }
}
|
我们再次运行我们的程序,并在浏览器上指定正确的地址访问定义在HomeController的Action方法Data,会在浏览器中呈现如下图所示的结果。输出的结果体现了应用到Action方法Data上的四个ActionFilter执行的顺序,而这是和Filter对应的Order和Scope属性值是一致的.
关于Filter的提供还另一个值得深究的问题:我们在定义FilterAttribute的时候可以将应用在该类型上的AttributeUsageAttribute的AllowMultiple属性设置为False使它只能在同一个目标元素上应用一次。但是,我们依然可以在Action方法和所在的Controller类型上应用它们,甚至可以将它们注册为全局Filter,那么这些FilterAttribute都将有效吗?
我们现在就来通过实例来验证这一点。现在我们删除所有的FilterAttribute,定义如下一个类型为FooAttribute的ActionFilter,我们将应用在它上面的AttributeUsageAttribute特性的AllowMultiple属性设置为False.
1
2
3
4
5
6
7
8
|
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple =
false
)]
public
class
FooAttribute : FilterAttribute, IActionFilter
{
public
void
OnActionExecuted(ActionExecutedContext filterContext)
{ }
public
void
OnActionExecuting(ActionExecutingContext filterContext)
{ }
}
|
现在我们将该FooAttribute特性同时应用在HomeController类型和Action方法Data上,然后在Global.asax中注册一个针对FooAttribute特性的全局Filter.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
[Foo]
public
class
HomeController : Controller
{
//其他成员
[Foo]
public
void
Data()
{ }
}
public
class
MvcApplication : System.Web.HttpApplication
{
//其他成员
protected
void
Application_Start()
{
//其他操作
//RegisterGlobalFilters(GlobalFilters.Filters);
GlobalFilters.Filters.Add(
new
FooAttribute());
}
}
|
现在我们直接运行我们的程序,开启的浏览器中会呈现出如图7-7所示的结果。可以清楚地看到虽然我们 在三个地方注册了FooAttribute,但是由于该特性的AllowMultiple属性为False,所以只有其中一个FooAttribute最终是有效的.
对于AllowMultiple属性为False的FilterAttribute来说,如果我们以不同的Scope注册了多个,最终有效的是哪个呢?从上图可以看出,应用在Action方法(Scope为Action)上的FooAttribute是有效的。其实具体的逻辑是这样的:所有被创建的Filter按照Order+Scope进行排序(即Filter执行的顺序),取排在最后一个。对于我们的例子来说,提供的三个Filter具有相同的Order属性值(-1),所有最终会按照Scope(Scope、Controller和Action)进行排序,排在最后一个的自然是Scope为Action的Filter.
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,同时也希望多多支持我! 。
原文链接:http://www.cnblogs.com/artech/archive/2012/07/02/filter.html 。
最后此篇关于详解ASP.NET MVC的筛选器的文章就讲到这里了,如果你想了解更多关于详解ASP.NET MVC的筛选器的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我之前让 dll 注入(inject)器变得简单,但我有 Windows 7,我用 C# 和 C++ 做了它,它工作得很好!但是现在当我在 Windows 8 中尝试相同的代码时,它似乎没有以正确的方
我正在尝试制作一个名为 core-splitter 的元素,该元素在 1.0 中已弃用,因为它在我们的项目中起着关键作用。 如果您不知道 core-splitter 的作用,我可以提供一个简短的描述。
我有几个不同的蜘蛛,想一次运行所有它们。基于 this和 this ,我可以在同一个进程中运行多个蜘蛛。但是,我不知道如何设计一个信号系统来在所有蜘蛛都完成后停止 react 器。 我试过了: cra
有没有办法在达到特定条件时停止扭曲 react 器。例如,如果一个变量被设置为某个值,那么 react 器应该停止吗? 最佳答案 理想情况下,您不会将变量设置为一个值并停止 react 器,而是调用
https://code.angularjs.org/1.0.0rc9/angular-1.0.0rc9.js 上面的链接定义了外部js文件,我不知道Angular-1.0.0rc9.js的注入(in
我正在尝试运行一个函数并将服务注入(inject)其中。我认为这可以使用 $injector 轻松完成.所以我尝试了以下(简化示例): angular.injector().invoke( [ "$q
在 google Guice 中,我可以使用函数 createInjector 创建基于多个模块的注入(inject)器。 因为我使用 GWT.create 在 GoogleGin 中实例化注入(in
我在 ASP.NET Core 1.1 解决方案中使用配置绑定(bind)。基本上,我在“ConfigureServices Startup”部分中有一些用于绑定(bind)的简单代码,如下所示: s
我在 Spring MVC 中设置 initBinder 时遇到一些问题。我有一个 ModelAttribute,它有一个有时会显示的字段。 public class Model { privat
我正在尝试通过jquery post发布knockoutjs View 模型 var $form = $('#barcodeTemplate form'); var data = ko.toJS(vm
如何为包含多态对象集合的复杂模型编写自定义模型绑定(bind)程序? 我有下一个模型结构: public class CustomAttributeValueViewModel { publi
您好,我正在尝试实现我在 this article 中找到的扩展方法对于简单的注入(inject)器,因为它不支持开箱即用的特定构造函数的注册。 根据这篇文章,我需要用一个假的委托(delegate)
你好,我想自动注册我的依赖项。 我现在拥有的是: public interface IRepository where T : class public interface IFolderReposi
我正在使用 Jasmine 测试一些 Angular.js 代码。为此,我需要一个 Angular 注入(inject)器: var injector = angular.injector(['ng'
我正在使用 Matlab 代码生成器。不可能包含代码风格指南。这就是为什么我正在寻找一个工具来“ reshape ”、重命名和重新格式化生成的代码,根据我的: 功能横幅约定 文件横幅约定 命名约定 等
这个问题在这里已经有了答案: Where and why do I have to put the "template" and "typename" keywords? (8 个答案) 关闭 8
我开发了一种工具,可以更改某些程序的外观。为此,我需要在某些进程中注入(inject)一个 dll。 现在我基本上使用这个 approach .问题通常是人们无法注入(inject) dll,因为他们
我想使用 swing、spring 和 hibernate 编写一个 java 应用程序。 我想使用数据绑定(bind)器用 bean 的值填充 gui,并且我还希望它反射(reflect) gui
我有这段代码,当两个蜘蛛完成后,程序仍在运行。 #!C:\Python27\python.exe from twisted.internet import reactor from scrapy.cr
要点是 Spring Batch (v2) 测试框架具有带有 @Autowired 注释的 JobLauncherTestUtils.setJob。我们的测试套件有多个 Job 类提供者。因为这个类不
我是一名优秀的程序员,十分优秀!