有时候你想在调用action方法之前或者action方法之后处理一些逻辑,为了支持这个,ASP.NETMVC允许你创建action过滤器。Action过滤器是自定义的Attributes,用来标记添加Action方法之前或者Action方法之后的行为到控制器类中的Action方法中。
一些可能用到Action过滤器的地方有:
Action过滤器是通过继承ActionFilterAttribute类来实现的一个Attribute类。ActionFilterAttribute 是一个抽象类,提供了两个virtual的方法给我们重写,OnActionExecuting和OnActionExecuted。
ASP.NET MVC 框架会在调用Action方法之前调用你Action过滤器中的OnActionExecuting方法,在之后调用Action过滤器中的OnActionExecuted方法。当然在创建Action过滤器的时候你不需两个方法都实现。
下面的示例是在调用Action方法之前和之后的日志跟踪:

LoggingFilterAttribute
publicclass LoggingFilterAttribute : ActionFilterAttribute


{
public override void OnActionExecuting(FilterExecutingContext
filterContext)

{
filterContext.HttpContext.Trace.Write("Starting: "
+
filterContext.ActionMethod.Name);
}

public override void OnActionExecuted(FilterExecutedContext filterContext)

{
if (filterContext.Exception !=null)

{
filterContext.HttpContext.Trace.Write("Exception thrown");
}
}
}
Action Filter Context
OnActionExecuting方法有一个类型为FilterExecutingContext的参数,而OnActionExecuted方法有一个相应的类型为FilterExcutedContext的参数。两个Context类都是继承自FilterContext类,而FilterContext类继承自ControllerContext类并包含一个ActionMethod属性。你可以使用ActionMethod属性来坚定这个Action过滤器是应用到哪个Action方法上的。
FilterExecutingContext类包含一个 Cancel 的属性,允许你取消当前的Action。
FilterExcutedContext类包含一个Exception属性和一个ExceptionHandled属性。如果Exception属性为null,则没有异常在actionstack中,表明Action方法运行并没有发生错误。如果Exception属性不为null,则过滤器知道该怎么处理,过滤器处理完异常后会发出已经处理完的信号,然后将ExceptionHandled属性设为true。就算ExceptionHandled属性为true,堆栈中添加到其他Action方法的OnActionExcetued方法将会照常被调用,这种场景就如就算一个异常被处理了,日志记录filter一样照常执行。
用过滤器特性(Attribute)来标记一个Action方法
你可以将过滤器应用到任何一个你喜欢的Action方法上。下面的示例演示一个控制器中包含的用Action过滤器Attribute标记的Action方法。
public
class HomeController : Controller


{
[LoggingFilter]
public
void Index()

{
RenderView("Index");
}

[LoggingFilter]
public
void About()

{
RenderView("About");
}

[LoggingFilter]
public
void ClickMe()

{
HttpContext.Trace.Write("Button was clicked.");
InvokeAction("Index");
}
}
实现一个控制器范围的Action过滤器
ASP.NET MVC 控制器(Controller)类定义的OnActionExecuting 和OnActionExcuted方法你可以重写。当你重写一个或者这两个方法的时候,你实际上定义了一个将会应用到该控制器类中所有的Action方法的Action过滤器。严格来说,这个方法没有构成一个Action过滤器,但不管怎样,她们提供的功能是相似的。
在下面的示例中,控制器级别的OnActionExecuting和OnActionExecuted方法应用到控制器中所有的Action方法中:

控制器范围的Action Filter
public
class HomeController : Controller


{
public
void Index()

{
RenderView("Index");
}

public
void About()

{
RenderView("About");
}

public
void ClickMe()

{
HttpContext.Trace.Write("Button was clicked.");
InvokeAction("Index");
}

protected
override
void OnActionExecuting(FilterExecutingContext
filterContext)

{
filterContext.HttpContext.Trace.Write("Starting: "
+
filterContext.ActionMethod.Name);
}

protected
override
void OnActionExecuted(FilterExecutedContext
filterContext)

{
if (filterContext.Exception !=
null)

{
filterContext.HttpContext.Trace.Write("Exception thrown");
}
}
}
Action过滤器的作用范围
除了用Action过滤器标记一个Action方法外,你也可以用来标记一个完成的控制器类。如果这样的话,这个Action过滤器将会应用到该控制器的所有Action方法上。
另外,如果你的控制器类继承自别的控制器类,而基控制器类可能有它自己的Action过滤器Attributes。如果你在子类中重写了基控制器类的Action方法,则子类的该Action方法也会有它自己的从基类继承而来的Action过滤器Attributes。
Action过滤器的执行顺序
每一个Action过滤器都有一个 Order属性,用来决定Action过滤器在该范围内的执行顺序。Order属性必需是0(默认值)或者更大的整数值。省略Order属性则会给该过滤器的Order值为 -1, 表明为指明顺序。任何一个在同一范围的Action过滤器Order设为 -1的都将按不确定的顺序执行,单在此之前过滤器有一个特定的顺序(注:下面会说到).
当设置Order属性的值的时候,必需指定一个唯一的值。如果两个或者更多的Action过滤器具有相同的Order属性值,将会抛出一个异常。
来看一个示例:
[Filter1(Order =
2)]
[Filter2(Order =
3)]
[Filter3(Order =
1)]
public
void Index()
{
RenderView("Index");
}
Filter的执行顺序为:Filter3 => Filter1 => Filter2.
在同一范围,Action过滤器按下面的顺序执行:
Action过滤器执行顺序的示例
下面的示例演示了一个包含两个Action过滤器的MVC程序。DebugFilter 过滤器写trace信息,而ThrowExceptionFilter 过滤器引起一个异常。这个程序也包含一个基控制器和一个子控制器和一个视图。

DebugFilter 过滤器
public
class DebugFilterAttribute : ActionFilterAttribute


{
public
static
void Reset()

{
counter =
1;
indent =
0;
incrementIndex =
true;
}

public
static
int Counter

{
get

{
return counter++;
}
}
static
int counter

{
get

{
return (int)(HttpContext.Current.Items["counter"] ??
1);
}
set

{
HttpContext.Current.Items["counter"] = value;
}
}

static
int indent

{
get

{
return (int)(HttpContext.Current.Items["indent"] ??
1);
}
set

{
HttpContext.Current.Items["indent"] = value;
}
}

static
bool incrementIndex

{
get

{
return (bool)(HttpContext.Current.Items["incrementIndex"] ??
true);
}
set

{
HttpContext.Current.Items["incrementIndex"] = value;
}
}


public
string Message
{ get; set; }


public
int Id
{ get; set; }

public
override
void OnActionExecuting(FilterExecutingContext
filterContext)

{
HttpContext.Current.Trace.Write(
"Action Filter",
string.Format("{0}: {3}(PRE) DebugFilter.OnActionExecuting"
+
" - Order={1} Message='{2}'",
Counter,
this.Order,
this.Message,
Indent));
}

public
static
string Indent

{
get

{
indent += (incrementIndex ?
1 : -1);
string indentText =
string.Empty;
for (int i =
0; i < indent; i++)
indentText +=
"
";
return indentText;
}
}

public
static
void StartDecrement()

{
incrementIndex =
false;
}
}
下面的Action过滤器在调用的时候将会抛出一个异常:
public
class ThrowExceptionFilter : DebugFilterAttribute


{
public
override
void
OnActionExecuting(
System.Web.Mvc.FilterExecutingContext filterContext)

{
base.OnActionExecuting(filterContext);
DebugFilterAttribute.StartDecrement();
throw
new InvalidOperationException(
"Exception thrown by the filter");
}
}
下面的是定义一个应用了Action过滤器的基控制器类:
[DebugFilter(Message =
"(CONTROLLER) MyBaseController", Order =
1)]
[DebugFilter(Message =
"(CONTROLLER) MyBaseController", Order=2)]
public
class MyBaseController : Controller


{
[ControllerAction]
[DebugFilter(Message =
"(ACTION) MyBaseController.Index()", Order=2)]
[DebugFilter(Message =
"(ACTION) MyBaseController.Index()", Order=1)]
public
virtual
void Index()

{
RenderView("Index");
}
}
下面的是子控制器类,注意这里重写了OnActionExecuting 方法:
MyDerivedController
[DebugFilter(Message =
"(CONTROLLER) MyDerivedController", Order =
2)]
[DebugFilter(Message =
"(CONTROLLER) MyDerivedController", Order=1)]
public
class MyDerivedController : MyBaseController


{
[ControllerAction]
[DebugFilter(Message =
"(ACTION) MyDerivedController.Index()", Order=1)]
[DebugFilter(Message =
"(ACTION) MyDerivedController.Index()", Order =
2)]
public
override
void Index()

{
base.Index();
HttpContext.Trace.Write(
"Action Filter",
string.Format("{0}: {1}(ACTION) "
+
"MyDerivedController.Index()",
DebugFilterAttribute.Counter,
DebugFilterAttribute.Indent));
DebugFilterAttribute.StartDecrement();
}

protected
override
void OnActionExecuting(FilterExecutingContext filterContext)

{
//The Beginning
DebugFilterAttribute.Reset();

HttpContext.Trace.Write(
"Action Filter",
string.Format("{0}: {1}(PRE) "
+
"MyDerviedController.OnActionExecuting VIRTUAL METHOD",
DebugFilterAttribute.Counter,
DebugFilterAttribute.Indent));
}
}
下面的是显示trace的视图页:
View

<%
@ Page Language="C#" CodeBehind="Index.aspx.cs" Inherits="ActionFilterTests.Views.MyDerived.Index" Trace="true"
%>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml"
>
<head runat="server">
<title>Attribute Filter Test</title>
</head>
<body>
<form id="form1" runat="server">
<div>
Hello World
</div>
</form>
</body>
</html>
下面是程序运行时的输出结果:Action Filter 1: (PRE) MyDerviedController.OnActionExecuting VIRTUAL METHOD
Action Filter 2: (PRE) DebugFilter.OnActionExecuting - Order=1 Message='(CONTROLLER) MyBaseController
Action Filter 3: (PRE) DebugFilter.OnActionExecuting - Order=2 Message='(CONTROLLER) MyBaseController
Action Filter 4: (PRE) DebugFilter.OnActionExecuting - Order=1 Message='(CONTROLLER) MyDerivedController
Action Filter 5: (PRE) DebugFilter.OnActionExecuting - Order=2 Message='(CONTROLLER) MyDerivedController
Action Filter 6: (PRE) DebugFilter.OnActionExecuting - Order=1 Message='(ACTION) MyDerivedController.Index()
Action Filter 7: (PRE) DebugFilter.OnActionExecuting - Order=2 Message='(ACTION) MyDerivedController.Index()
Action Filter 8: (ACTION) MyDerivedController.Index()
注:本文参考自http://quickstarts.asp.net/3-5-extensions/mvc/ActionFiltering.aspx
一些可能用到Action过滤器的地方有:
- 日志
- 身份验证和授权 - 限制用户的访问
- 输出缓存 - 保存一个Action的结果
- 网络爬虫的过滤
- 本地化
- 动态Action - 将一个Action注入到控制器中
Action过滤器是通过继承ActionFilterAttribute类来实现的一个Attribute类。ActionFilterAttribute 是一个抽象类,提供了两个virtual的方法给我们重写,OnActionExecuting和OnActionExecuted。
ASP.NET MVC 框架会在调用Action方法之前调用你Action过滤器中的OnActionExecuting方法,在之后调用Action过滤器中的OnActionExecuted方法。当然在创建Action过滤器的时候你不需两个方法都实现。
下面的示例是在调用Action方法之前和之后的日志跟踪:
publicclass LoggingFilterAttribute : ActionFilterAttribute

{
public override void OnActionExecuting(FilterExecutingContext
filterContext)
{
filterContext.HttpContext.Trace.Write("Starting: "+
filterContext.ActionMethod.Name);
} 
public override void OnActionExecuted(FilterExecutedContext filterContext)
{
if (filterContext.Exception !=null)
{
filterContext.HttpContext.Trace.Write("Exception thrown");
}
}
}Action Filter Context
OnActionExecuting方法有一个类型为FilterExecutingContext的参数,而OnActionExecuted方法有一个相应的类型为FilterExcutedContext的参数。两个Context类都是继承自FilterContext类,而FilterContext类继承自ControllerContext类并包含一个ActionMethod属性。你可以使用ActionMethod属性来坚定这个Action过滤器是应用到哪个Action方法上的。
FilterExecutingContext类包含一个 Cancel 的属性,允许你取消当前的Action。
FilterExcutedContext类包含一个Exception属性和一个ExceptionHandled属性。如果Exception属性为null,则没有异常在actionstack中,表明Action方法运行并没有发生错误。如果Exception属性不为null,则过滤器知道该怎么处理,过滤器处理完异常后会发出已经处理完的信号,然后将ExceptionHandled属性设为true。就算ExceptionHandled属性为true,堆栈中添加到其他Action方法的OnActionExcetued方法将会照常被调用,这种场景就如就算一个异常被处理了,日志记录filter一样照常执行。
用过滤器特性(Attribute)来标记一个Action方法
你可以将过滤器应用到任何一个你喜欢的Action方法上。下面的示例演示一个控制器中包含的用Action过滤器Attribute标记的Action方法。
publicclass HomeController : Controller


{
[LoggingFilter]
publicvoid Index()

{
RenderView("Index");
} 
[LoggingFilter]
publicvoid About()

{
RenderView("About");
} 
[LoggingFilter]
publicvoid ClickMe()

{
HttpContext.Trace.Write("Button was clicked.");
InvokeAction("Index");
}
}实现一个控制器范围的Action过滤器
ASP.NET MVC 控制器(Controller)类定义的OnActionExecuting 和OnActionExcuted方法你可以重写。当你重写一个或者这两个方法的时候,你实际上定义了一个将会应用到该控制器类中所有的Action方法的Action过滤器。严格来说,这个方法没有构成一个Action过滤器,但不管怎样,她们提供的功能是相似的。
在下面的示例中,控制器级别的OnActionExecuting和OnActionExecuted方法应用到控制器中所有的Action方法中:
publicclass HomeController : Controller


{
publicvoid Index()

{
RenderView("Index");
}
publicvoid About()

{
RenderView("About");
}
publicvoid ClickMe()

{
HttpContext.Trace.Write("Button was clicked.");
InvokeAction("Index");
}
protectedoverride
void OnActionExecuting(FilterExecutingContext
filterContext)
{
filterContext.HttpContext.Trace.Write("Starting: "+
filterContext.ActionMethod.Name);
}
protectedoverride
void OnActionExecuted(FilterExecutedContext
filterContext)
{
if (filterContext.Exception !=null)

{
filterContext.HttpContext.Trace.Write("Exception thrown");
}
}
}Action过滤器的作用范围
除了用Action过滤器标记一个Action方法外,你也可以用来标记一个完成的控制器类。如果这样的话,这个Action过滤器将会应用到该控制器的所有Action方法上。
另外,如果你的控制器类继承自别的控制器类,而基控制器类可能有它自己的Action过滤器Attributes。如果你在子类中重写了基控制器类的Action方法,则子类的该Action方法也会有它自己的从基类继承而来的Action过滤器Attributes。
Action过滤器的执行顺序
每一个Action过滤器都有一个 Order属性,用来决定Action过滤器在该范围内的执行顺序。Order属性必需是0(默认值)或者更大的整数值。省略Order属性则会给该过滤器的Order值为 -1, 表明为指明顺序。任何一个在同一范围的Action过滤器Order设为 -1的都将按不确定的顺序执行,单在此之前过滤器有一个特定的顺序(注:下面会说到).
当设置Order属性的值的时候,必需指定一个唯一的值。如果两个或者更多的Action过滤器具有相同的Order属性值,将会抛出一个异常。
来看一个示例:
[Filter1(Order =
2)]
[Filter2(Order =
3)]
[Filter3(Order =
1)]
public
void Index()
{
RenderView("Index");
}
Filter的执行顺序为:Filter3 => Filter1 => Filter2.
在同一范围,Action过滤器按下面的顺序执行:
- OnActionExecuting virtual method of the controller.
- OnActionExecuting method of any filters that are applied to the current controller, in this order:
- Base class
- Any derived class
- Base class
- OnActionExecuting method of filters that are applied to the action method, in this order:
- Base class
- Derived class
- Base class
- Action method
- OnActionExecuted method of filters that are applied to the action method, in this order:
- Derived class
- Base class
- Derived class
- OnActionExecuted method of filters that are applied to the current controller, in this order:
- Derived class
- Base class
- Derived class
- OnActionExecuted virtual method of the controller.
Action过滤器执行顺序的示例
下面的示例演示了一个包含两个Action过滤器的MVC程序。DebugFilter 过滤器写trace信息,而ThrowExceptionFilter 过滤器引起一个异常。这个程序也包含一个基控制器和一个子控制器和一个视图。
publicclass DebugFilterAttribute : ActionFilterAttribute


{
publicstatic
void Reset()

{
counter =1;
indent =0;
incrementIndex =true;
}
publicstatic
int Counter

{
get
{
return counter++;
}
}
staticint counter

{
get
{
return (int)(HttpContext.Current.Items["counter"] ??1);
}
set
{
HttpContext.Current.Items["counter"] = value;
}
}
staticint indent

{
get
{
return (int)(HttpContext.Current.Items["indent"] ??1);
}
set
{
HttpContext.Current.Items["indent"] = value;
}
}
staticbool incrementIndex

{
get
{
return (bool)(HttpContext.Current.Items["incrementIndex"] ??true);
}
set
{
HttpContext.Current.Items["incrementIndex"] = value;
}
}

publicstring Message
{ get; set; }

publicint Id
{ get; set; }
publicoverride
void OnActionExecuting(FilterExecutingContext
filterContext)
{
HttpContext.Current.Trace.Write(
"Action Filter",
string.Format("{0}: {3}(PRE) DebugFilter.OnActionExecuting"
+" - Order={1} Message='{2}'",
Counter,
this.Order,
this.Message,
Indent));
}
publicstatic
string Indent

{
get
{
indent += (incrementIndex ?1 : -1);
string indentText =string.Empty;
for (int i =0; i < indent; i++)
indentText +="
";
return indentText;
}
}
publicstatic
void StartDecrement()

{
incrementIndex =false;
}
}下面的Action过滤器在调用的时候将会抛出一个异常:
publicclass ThrowExceptionFilter : DebugFilterAttribute


{
publicoverride
void
OnActionExecuting(
System.Web.Mvc.FilterExecutingContext filterContext)
{
base.OnActionExecuting(filterContext);
DebugFilterAttribute.StartDecrement();
thrownew InvalidOperationException(
"Exception thrown by the filter");
}
}下面的是定义一个应用了Action过滤器的基控制器类:
[DebugFilter(Message ="(CONTROLLER) MyBaseController", Order =
1)]
[DebugFilter(Message ="(CONTROLLER) MyBaseController", Order=2)]
publicclass MyBaseController : Controller


{
[ControllerAction]
[DebugFilter(Message ="(ACTION) MyBaseController.Index()", Order=2)]
[DebugFilter(Message ="(ACTION) MyBaseController.Index()", Order=1)]
publicvirtual
void Index()

{
RenderView("Index");
}
}下面的是子控制器类,注意这里重写了OnActionExecuting 方法:
[DebugFilter(Message ="(CONTROLLER) MyDerivedController", Order =
2)]
[DebugFilter(Message ="(CONTROLLER) MyDerivedController", Order=1)]
publicclass MyDerivedController : MyBaseController


{
[ControllerAction]
[DebugFilter(Message ="(ACTION) MyDerivedController.Index()", Order=1)]
[DebugFilter(Message ="(ACTION) MyDerivedController.Index()", Order =
2)]
publicoverride
void Index()

{
base.Index();
HttpContext.Trace.Write(
"Action Filter",
string.Format("{0}: {1}(ACTION) "
+"MyDerivedController.Index()",
DebugFilterAttribute.Counter,
DebugFilterAttribute.Indent));
DebugFilterAttribute.StartDecrement();
}
protectedoverride
void OnActionExecuting(FilterExecutingContext filterContext)

{
//The Beginning
DebugFilterAttribute.Reset();
HttpContext.Trace.Write(
"Action Filter",
string.Format("{0}: {1}(PRE) "
+"MyDerviedController.OnActionExecuting VIRTUAL METHOD",
DebugFilterAttribute.Counter,
DebugFilterAttribute.Indent));
}
}下面的是显示trace的视图页:

<%
@ Page Language="C#" CodeBehind="Index.aspx.cs" Inherits="ActionFilterTests.Views.MyDerived.Index" Trace="true"%>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Attribute Filter Test</title>
</head>
<body>
<form id="form1" runat="server">
<div>
Hello World
</div>
</form>
</body>
</html>下面是程序运行时的输出结果:Action Filter 1: (PRE) MyDerviedController.OnActionExecuting VIRTUAL METHOD
Action Filter 2: (PRE) DebugFilter.OnActionExecuting - Order=1 Message='(CONTROLLER) MyBaseController
Action Filter 3: (PRE) DebugFilter.OnActionExecuting - Order=2 Message='(CONTROLLER) MyBaseController
Action Filter 4: (PRE) DebugFilter.OnActionExecuting - Order=1 Message='(CONTROLLER) MyDerivedController
Action Filter 5: (PRE) DebugFilter.OnActionExecuting - Order=2 Message='(CONTROLLER) MyDerivedController
Action Filter 6: (PRE) DebugFilter.OnActionExecuting - Order=1 Message='(ACTION) MyDerivedController.Index()
Action Filter 7: (PRE) DebugFilter.OnActionExecuting - Order=2 Message='(ACTION) MyDerivedController.Index()
Action Filter 8: (ACTION) MyDerivedController.Index()
注:本文参考自http://quickstarts.asp.net/3-5-extensions/mvc/ActionFiltering.aspx

添加至收藏夹