知无涯

吾生也有涯,而知也无涯,以有涯随无涯,殆已
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

Asp.net mvc Preview 3 学习 - Action 过滤器

Posted on 2008-08-14 16:17  Fred du  阅读(379)  评论(0编辑  收藏  举报

介绍

在Action方法执行前后在一些情况下经常需要增加一些业务逻辑处理,比如如下一些情况Action过滤器就派上用场了:

  • 在调试过程中跟踪记录一些用户活动状态
  • 在对访问受限的资源进行验证和授权
  • 输出缓存:保存用户执行结果
  • 网络爬虫过滤:针对客户端类型改变应用程序行为
  • 本地化:设置本地语言
  • 动态Action:注入一个Action方法到一个Controller中

实现一个Action 过滤器

作为特性类实行的Action 过滤器继承ActionFilterAttribute.

ActionFilterAttribute是一个抽象类,有四个虚函数可以重写,而且必须至少重写四个当中的一个:

  • OnActionExecuting 在任何被标示了自定义的Action过滤器特性的Action方法执行之前被调用。
  • OnActionExecuted 在任何被标示了自定义的Action过滤器特性的Action方法完成之后被调用。
  • OnResultExecuting 在被Action调用之后产生ActionResult 实例被返回之前被调用
  • OnResultExecuted 在被Action调用之后产生ActionResult 实例被返回之后被调用

下面的例子演示了在一个Action方法被调用之前与之后过滤器记录了一些跟踪调试信息:

[C#]



Code

Action Filter Context
每个Action filtering的事件处理都有一个context对象作为参数。下面列表显示了每个事件处理的方法和context对象类型:

  • OnActionExecting :ActionExecutingContext
  • OnActionExecutedActionExecutedContext
  • OnResultExecutingResultExecutingContext
  • OnResultExecutedResultExecutedContext

所有的context对象都继承自ControllerContext 类,包含一个ActionMethod 属性。你能使用ActionMethod 属性验证当前被过滤得哪个action被执行。

ActionExecutingContextResutlExecutingContext 类包含一个Cancel 属性允许你取消当前的action。

The ActionExecutedContent and ResultExecutedContext classes contain an Exception property and an ExceptionHandled property. If the Exception property is null, it indicates that no error occurred when the action method ran. If the Exception property is not null and the filter knows how to handle the exception, the filter can handle the exception and then signal that it has done so by setting the ExceptionHandled property to true. Even if the ExceptionHandled property is true, the OnActionExecuted or OnResultExecuted method of any additional action filters in the stack will be called and exception information will be passed to them. This enables scenarios such as letting a logging filter log an exception even though the exception has been handled. In general, an action filter should not handle an exception unless the error is specific to that filter.

ActionExecutedContentResultExecutedContext 类包含一个Exception 属性和一个ExceptionHandled 属性。假如Exception属性为空它表示在action方法运行的时候没有错误发生。 假如Exception 属性不为空过滤器知道如何处理异常,过滤器能处理异常它就会通过设置ExceptionHandled 属性为true来发出它已经做的处理信号。假如ExceptionHandled 为true,在堆栈中任何加了Action 过滤器的OnActionExecutedOnResultExecuted 方法将会被调用,异常信息将被传送给他们。这将能够在一个异常发生的时候日志过滤器就记录该异常的功能。通常,action过滤器中不应该处理异常,除非错误对于过滤器是特殊的。

在一个Action方法标示一个过滤器属性

你可以应用一个action过滤器到你所需要的很多action方法中。下面例子演示了一个controller包含一个被标示了一个action过滤器的action方法。在这个例子中,所有在这个controller的action方法都将调用同样的action过滤器。

Code

提示:

假如你想要将一个action过滤器作用到一个controller的所有action方法中,你可以在controller上面标示一个过滤器属性。这个作用相同于将过滤器加到每个action方法中。

实现一个controller域的action过滤器

ASP.NET MVC Controller类定义了可以被重写的OnActionExecutingOnActionExecuted 的方法。当你重写了它们中的一个或两个时,你的逻辑将在这个controller的所有action方法之前或之后执行。这个功能很像action过滤器,但是方法是controller域内的。

下面的例子演示了controller级的OnActionExecutingOnActionExecuted方法在一个controller的所有action方法被应用。

 

Code

action过滤器的范围

action方法继承过来的。



理解action过滤器是如何在一起工作是容易的,action方法被聚集在范围里。一个范围定义了特性所应用的地点,比如它是标示一个类还是一个方法,



它是标示一个基类还是一个继承类。





Order of Execution for Action Filters











Each action filter has an Order property, which is used to determine the order that filters are executed in the scope of the filter. The Order property takes an integer value that must be 0 (default) or higher (with one exception). Omitting the Order property gives the filter an order value of -1, which indicates an unspecified order. Any action filters within a scope whose Order property is set to -1 will be executed in a nondeterministic order, but before the filters that have a specified order.















When an Order property of a filter is specified, it must be set to a unique value within a scope. If two or more action filters within a scope have the same Order property value, an exception is thrown.















The following example shows how the Order property affects the order in which action filters are executed.















[C#]















[Filter1(Order = 2)]















[Filter2(Order = 3)]















[Filter3(Order = 1)]















public void Index()















{















View("Index");















}































除用一个action过滤器标示单个的action方法之外,你也可以用action过滤器标示一个controller类。















这种实例下,过滤器将应用到该controller的所有action方法。















 















此外,如果你的controller从另外一个controller继承过来,父controller(base controller)可以有它自己的action-filer属性。















同样的,将如你的controller从父controller重写了一个action方法,该方法可以由它自己的action-filter的特性和它从重写的































In the previous example, the action filters would be executed in the following order: Filter3, Filter1, and then Filter2.















Within a scope, action filter methods are typically executed in the following order:















  1. OnActionExecuting method of the controller.

  2. OnActionExecuting method of any filters that are applied to the current controller, in this order:

    1. Base class

    2. Any derived class

  3. OnActionExecuting method of filters that are applied to the action method, in this order:

    1. Base class

    2. Derived class

  4. Action method

  5. OnActionExecuted method of filters that are applied to the action method, in this order:

    1. Derived class

    2. Base class

  6. OnActionExecuted method of filters that are applied to the current controller, in this order:

    1. Derived class

    2. Base class

  7. OnActionExecuted method of the controller.

Example of Action Filter Order of Execution

















The following example shows an MVC application that contains two action filters. The DebugFilter filter writes trace messages, and the ThrowExceptionFilter filter causes an exception. The application also contains a base controller, a derived controller, and a view.















The following example shows the class that defines the DebugFilter filter. The filter uses some static methods and properties to trace filter depth and to control indentation of the output.















[C#]















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(ActionExecutingContext















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 override void OnActionExecuted(ActionExecutedContext















filterContext)















{















HttpContext.Current.Trace.Write(















"Action Filter",















string.Format("{0}: {3}(POST) DebugFilter.OnActionExecuted - 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;















}















}















The following example shows a class that defines the base controller with action filters applied.
[C#]















[DebugFilter(Message = "(CONTROLLER) MyBaseController", Order = 1)]















[DebugFilter(Message = "(CONTROLLER) MyBaseController", Order=2)]















public class MyBaseController : Controller















{















[DebugFilter(Message = "(ACTION) MyBaseController.Index()", Order=2)]















[DebugFilter(Message = "(ACTION) MyBaseController.Index()", Order=1)]















public virtual ActionResult Index()















{















return View();















}















}















The following example shows a class that defines the derived controller with action filters applied. Notice that this controller implements its OnActionExecuting and OnActionExecuted methods.















[C#]















[DebugFilter(Message = "(CONTROLLER) MyDerivedController", Order = 2)]















[DebugFilter(Message = "(CONTROLLER) MyDerivedController", Order=1)]















public class MyDerivedController : MyBaseController















{















[DebugFilter(Message = "(ACTION) MyDerivedController.Index()", Order=1)]















[DebugFilter(Message = "(ACTION) MyDerivedController.Index()", Order = 2)]















// Uncomment the following line to cause an exception to be















// thrown and to see what happens in the trace messages.















//[ThrowExceptionFilter(Message = "(ACTION) Exception thrown!", Order=3)]















public override ActionResult Index()















{















base.Index();















HttpContext.Trace.Write("Action Filter",















string.Format("{0}: {1}(ACTION) MyDerivedController.Index()",















DebugFilterAttribute.Counter,















DebugFilterAttribute.Indent));















DebugFilterAttribute.StartDecrement();















return View();















}































protected override void OnActionExecuting(ActionExecutingContext















filterContext)















{















// Processing begins here.















DebugFilterAttribute.Reset();































HttpContext.Trace.Write("Action Filter", string.Format("{0}: {1}(PRE) MyDerviedController.OnActionExecuting VIRTUAL METHOD",















DebugFilterAttribute.Counter,















DebugFilterAttribute.Indent));















}































protected override void OnActionExecuted(ActionExecutedContext















filterContext)















{















HttpContext.Trace.Write("Action Filter", string.Format("{0}: {1}(POST) MyDerviedController.OnActionExecuted VIRTUAL METHOD",















DebugFilterAttribute.Counter,















DebugFilterAttribute.Indent));































if (filterContext.Exception != null)















filterContext.ExceptionHandled = true;































// Processing ends here.















((MyDerivedController)filterContext.Controller).View("Index");















}















}

The following example shows the Index view for the application whose Trace property is set to true.



<%@ 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>



The following example shows the output trace messages that are displayed when this application runs.

(PRE) MyDerviedController.OnActionExecuting VIRTUAL METHOD

(PRE) DebugFilter.OnActionExecuting - Order=1 Message='(CONTROLLER) MyBaseController

(PRE) DebugFilter.OnActionExecuting - Order=2 Message='(CONTROLLER) MyBaseController

(PRE) DebugFilter.OnActionExecuting - Order=1 Message='(CONTROLLER) MyDerivedController

(PRE) DebugFilter.OnActionExecuting - Order=2 Message='(CONTROLLER) MyDerivedController

(PRE) DebugFilter.OnActionExecuting - Order=1 Message='(ACTION) MyBaseController.Index()

(PRE) DebugFilter.OnActionExecuting - Order=2 Message='(ACTION) MyBaseController.Index()

(PRE) DebugFilter.OnActionExecuting - Order=1 Message='(ACTION) MyDerivedController.Index()

(PRE) DebugFilter.OnActionExecuting - Order=2 Message='(ACTION) MyDerivedController.Index()

(ACTION) MyDerivedController.Index() 0.010142769541939 0.008739

(POST) DebugFilter.OnActionExecuted - Order=2 Message='(ACTION) MyDerivedController.Index()

(POST) DebugFilter.OnActionExecuted - Order=1 Message='(ACTION) MyDerivedController.Index()

(POST) DebugFilter.OnActionExecuted - Order=2 Message='(ACTION) MyBaseController.Index()

(POST) DebugFilter.OnActionExecuted - Order=1 Message='(ACTION) MyBaseController.Index()

(POST) DebugFilter.OnActionExecuted - Order=2 Message='(CONTROLLER) MyDerivedController

(POST) DebugFilter.OnActionExecuted - Order=1 Message='(CONTROLLER) MyDerivedController

(POST) DebugFilter.OnActionExecuted - Order=2 Message='(CONTROLLER) MyBaseController

(POST) DebugFilter.OnActionExecuted - Order=1 Message='(CONTROLLER) MyBaseController

(POST) MyDerviedController.OnActionExecuted VIRTUAL METHOD



 

Technorati : .net, asp.net mvc