首页 > 代码库 > asp.net MVC之Action过滤器浅析

asp.net MVC之Action过滤器浅析

在asp.net MVC中,Action过滤器是一大利器,它可以在以下两个步骤执行相关的代码:

1.执行Action方法之前:OnActionExecuting

2.Action方法执行完毕后:OnActionExecuted

一般我们自定义的Action过滤器会继承FilterAttribute类和IActionFilter接口。

FilterAttribute类有两个关键属性:

AllowMultiple:布尔型,指示是否可指定筛选器特性的多个实例。如果可指定筛选器特性的多个实例,则为 true;否则为 false。

Order:int整型,获取或者设置执行操作筛选器的顺序。该属性后面会讲到。

 

IActionFilter接口有两个关键方法:

void OnActionExecuting(ActionExecutingContext filterContext):在进入Action之前执行该方法。

void OnActionExecuted(ActionExecutedContext filterContext):Action方法执行完毕之后立刻执行该方法。

 

接下来让我们用代码亲自实践。

首先自定义一个Action过滤器:

    public class MyFirstActionFilterAttribute : FilterAttribute, IActionFilter {
        public void OnActionExecuting(ActionExecutingContext filterContext) {
            filterContext.HttpContext.Response.Write(string.Format("<h4 style=‘background-color:black;color:white;‘>{2} OnActionExecuting {0} {1}</h4>",
                filterContext.ActionDescriptor.ControllerDescriptor.ControllerName, filterContext.ActionDescriptor.ActionName, this.GetType().Name));
        }

        public void OnActionExecuted(ActionExecutedContext filterContext) {
            filterContext.HttpContext.Response.Write(string.Format("<h4 style=‘background-color:black;color:white;‘>{2} OnActionExecuted {0} {1}</h4>",
                filterContext.ActionDescriptor.ControllerDescriptor.ControllerName, filterContext.ActionDescriptor.ActionName,GetType().Name));
        }
    }

接着我们将该方法过滤器附加到一个Action上:

        [MyFirstActionFilter]    
        public ActionResult ActionFilterTest() {
            Response.Write("进入Action方法");
            return  new EmptyResult();
        }

执行结果如下:

技术分享

执行的顺序果然是 OnActionExecuting》Action》OnActionExecuted。

 

如果有很多Action过滤器附加到一个Action方法上,那么执行的顺序又是怎样的呢?相当于自上而下压栈式执行,可以将OnActionExecuting当做左大括号,OnActionExecuted当做右大括号。

我们继续自定义两个Action过滤器来实践一下:

    public class MySecondActionFilterAttribute : FilterAttribute, IActionFilter {
        public void OnActionExecuting(ActionExecutingContext filterContext) {

            filterContext.HttpContext.Response.Write(string.Format("<h4 style=‘background-color:yellow;color:red;‘>{2} OnActionExecuting {0} {1}</h4>",
                filterContext.ActionDescriptor.ControllerDescriptor.ControllerName, filterContext.ActionDescriptor.ActionName, this.GetType().Name));
        }

        public void OnActionExecuted(ActionExecutedContext filterContext) {
            filterContext.HttpContext.Response.Write(string.Format("<h4 style=‘background-color:yellow;color:red;‘>{2} OnActionExecuted {0} {1}</h4>",
                filterContext.ActionDescriptor.ControllerDescriptor.ControllerName, filterContext.ActionDescriptor.ActionName, GetType().Name));
        }
    }
public class MyThirdActionFilterAttribute : FilterAttribute, IActionFilter { public void OnActionExecuting(ActionExecutingContext filterContext) { filterContext.HttpContext.Response.Write(string.Format("<h4 style=‘background-color:aliceblue;color:blue;‘>{2} OnActionExecuting {0} {1}</h4>", filterContext.ActionDescriptor.ControllerDescriptor.ControllerName, filterContext.ActionDescriptor.ActionName, this.GetType().Name)); } public void OnActionExecuted(ActionExecutedContext filterContext) { filterContext.HttpContext.Response.Write(string.Format("<h4 style=‘background-color:aliceblue;color:blue;‘>{2} OnActionExecuted {0} {1}</h4>", filterContext.ActionDescriptor.ControllerDescriptor.ControllerName, filterContext.ActionDescriptor.ActionName, GetType().Name)); } }

附加到同一个Action方法上:

        [MyFirstActionFilter]
        [MySecondActionFilter]
        [MyThirdActionFilter]
        public ActionResult ActionFilterTest() {
            Response.Write("进入Action方法");
            return  new EmptyResult();
        }

执行的结果如下图所示:

技术分享

执行的顺序果然是自上而下、压栈式执行。这是默认的方式。

 

我们还可以通过设置每个Action过滤器的Order属性来自定义它们的执行顺序。这就是Action过滤器需要继承FilterAttribute的原因。

接下来我们打乱每个Action过滤器的位置,并设置每个Action过滤器的Order属性。如下代码:

        [MyThirdActionFilter(Order = 3)]
        [MySecondActionFilter(Order = 2)]
        [MyFirstActionFilter(Order =1)]
        public ActionResult ActionFilterTest() {
            Response.Write("进入Action方法");
            return  new EmptyResult();
        }

运行程序,看一看执行的结果:

技术分享

果然是根据Order的升序来执行的,且还是压栈式执行。

 

介绍一个实际的用法。如果遇到跨域的情况,可以在OnActionExecuting方法中判断当前用户码和相关标识,表示是否可以跨域处理。

类似如下代码:

        public void OnActionExecuting(ActionExecutingContext filterContext) {
            bool isAllowCrossDomain = false;
            //判断用户码和相关标识
            //......
            //判断完毕并设置isAllowCrossDomain
            //如果允许跨域
            if (isAllowCrossDomain) {
                //在此返回正确结果
            }
            else {
                //返回错误代码和消息说明
            }
            filterContext.HttpContext.Response.AddHeader("Access-Control-Allow-Origin", "*");
        }

 

asp.net MVC之Action过滤器浅析