zoukankan      html  css  js  c++  java
  • ASP.NET MVC : Action过滤器(Filtering)

    http://www.cnblogs.com/QLeelulu/archive/2008/03/21/1117092.html

    ASP.NET MVC : Action过滤器(Filtering)

    相关文章:

    1. ASP.NET MVC URL Routing 学习
    2. AP.NET MVC : 控制器 和 控制器Actions
    3. ASP.NET MVC 学习: 视图  

    有时候你想在调用action方法之前或者action方法之后处理一些逻辑,为了支持这个,ASP.NET MVC允许你创建action过滤器。Action过滤器是自定义的Attributes,用来标记添加Action方法之前或者Action方法之后的行为到控制器类中的Action方法中。

    一些可能用到Action过滤器的地方有:

    • 日志
    • 身份验证和授权 - 限制用户的访问
    • 输出缓存 - 保存一个Action的结果
    • 网络爬虫的过滤
    • 本地化
    • 动态Action - 将一个Action注入到控制器中

    实现一个Action过滤器

    Action过滤器是通过继承ActionFilterAttribute类来实现的一个Attribute类。ActionFilterAttribute 是一个抽象类,提供了两个virtual的方法给我们重写,OnActionExecutingOnActionExecuted

    ASP.NET MVC 框架会在调用Action方法之前调用你Action过滤器中的OnActionExecuting方法,在之后调用Action过滤器中的OnActionExecuted方法。当然在创建Action过滤器的时候你不需两个方法都实现。

    下面的示例是在调用Action方法之前和之后的日志跟踪:


    public class 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,则没有异常在action stack中,表明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方法中:


    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过滤器按下面的顺序执行:

    • 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

    • OnActionExecuting method of filters that are applied to the action method, in this order:
      • Base class

      • Derived class

    • Action method
    • OnActionExecuted method of filters that are applied to the action method, in this order:
      • Derived class

      • Base class

    • OnActionExecuted method of filters that are applied to the current controller, in this order:
      • Derived class

      • Base class

    • OnActionExecuted virtual method of the controller.

    可以看到OnActionExecuted 和 OnActionExecuting 的执行顺序是反过来的。

    Action过滤器执行顺序的示例

    下面的示例演示了一个包含两个Action过滤器的MVC程序。DebugFilter 过滤器写trace信息,而ThrowExceptionFilter 过滤器引起一个异常。这个程序也包含一个基控制器和一个子控制器和一个视图。


    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 方法:

    [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的视图页:

    <%@ 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
  • 相关阅读:
    操作系统之磁盘结构笔记
    Linux 操作系统位数(32or64)识别
    手把手教你mysql(十)索引
    Linux命令 — 设置或查看网络配置命令ifconfig
    字符数组的排列
    android 加载图片防止内存溢出
    eCos系统CPU负载测量
    模糊控制——理论基础(4模糊推理)
    模糊控制——理论基础(3模糊关系及其运算)
    模糊控制——理论基础(2隶属函数)
  • 原文地址:https://www.cnblogs.com/zkwarrior/p/4794832.html
Copyright © 2011-2022 走看看