MVC过滤器

MVC过滤器类型:
Authorization(授权),继承IAuthorizationFilter接口,用于限制进入Controller或Action
Action(行为),继承IActionFilter接口,用于进入Action之前或之后的处理
Result(结果),继承IResultFilter接口,用于返回结果之前或之后的处理
Exception(异常),继承IExceptionFilter接口,用于指定一个行为,这个被指定的行为处理某个Action或Controller里面抛出的异常

1.自定义授权

需要重写两个方法:

bool AuthorizeCore(HttpContextBase httpContext):授权验证的逻辑处理,返回true则通过授权,返回false则未通过。
void HandleUnauthorizedRequest(AuthorizationContext filterContext):这个方法是处理授权失败的事情。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace TestProject.Filters
{
    public class MyAuthorizeAttribute : AuthorizeAttribute
    {
        protected override bool AuthorizeCore(HttpContextBase httpContext)
        {
            //return base.AuthorizeCore(httpContext);
            string name = httpContext.Request["Name"];
            bool result = name == "jay";
            return result;//true:授权验证通过;false:授权验证失败。
        }


        protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
        {
            filterContext.HttpContext.Response.Redirect("/Home/Login");//若name不等于jay,验证失败,跳转到登录
            //base.HandleUnauthorizedRequest(filterContext);
        }
    }
}

使用方法:

[HttpGet]
        [MyAuthorize]
        public ActionResult ChangePassword(string Name)
        {
            return View();
        }

2.默认HandleError使用

在往常的开发中,想到异常处理的马上就会想到try/catch/finally语句块。
在MVC里面,万一在行为方法里面抛出了什么异常的,而那个行为方法或者控制器有用上HandleError过滤器的,
异常的信息都会在某一个视图显示出来,这个显示异常信息的视图默认是在Views/Shared/Error

HandleError的属性如下:

ExceptionType,Type类型,要处理的异常的类型,相当于Try/Catch语句块里Catch捕捉的类型,如果这里不填的话则表明处理所有异常
View,String,指定需要展示异常信息的视图,只需要视图名称就可以了,这个视图文件要放在Views/Shared文件夹里面
Master,String,指定要使用的母版视图的名称
Order,Int,指定过滤器被应用的顺序,默认是-1,而且优先级最高的是-1

示例:

[HandleError(ExceptionType = typeof(Exception))]
        public ActionResult ThrowErrorLogin()
        {
            throw new Exception("this is ThrowErrorLogin Action Throw");
        }

  注:需要修改web.config,<customErrors mode="On" />

3.自定义异常视图

通过@Model获取异常信息,它是一个ExceptionInfo类型的实例,
例如这里建了一个异常视图MyErrorPage.cshtml

@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <title>MyErrorPage</title>
</head>
<body>
    <div>
    <p>
        There was a <b>@Model.Exception.GetType().Name</b> 
        while rendering <b>@Model.ControllerName</b>'s 
        <b>@Model.ActionName</b> action. 
    </p> 
    <p style="color:Red"> 
        <b>@Model.Exception.Message</b> 
    </p> 
    <p>Stack trace:</p> 
    <pre style=" background-color:Orange">@Model.Exception.StackTrace</pre>
        </div>
</body>
</html>

它存放的路径是~/Views/Shared里面,像上面的行为方法如果要用异常信息渲染到这个视图上面,在控制器的处改成这样就可以了

[HandleError(ExceptionType = typeof(Exception), View = "MyErrorPage")]

4.自定义错误异常处理

这里的错误处理过滤器也可以自己来定义,做法是继承HandleErrorAttribute类,重写void OnException(ExceptionContext filterContext)方法,这个方法调用是为了处理未处理的异常,例如

public override void OnException(ExceptionContext filterContext)
        {
            //base.OnException(filterContext);
            if (!filterContext.ExceptionHandled && 
                filterContext.Exception.Message == "this is ThrowErrorLogin Action Throw")
            { 
                filterContext.ExceptionHandled=true;
                filterContext.HttpContext.Response.Write(filterContext.Exception.ToString());
            }
        }

这里用到的传入了一个ExceptionContext的对象,既可以从它那里获得请求的信息,又可以获取异常的信息,
它部分属性如下:

ActionDescriptor,ActionDescriptor,提供详细的操作方法
Result,ActionResult,结果的操作方法,过滤器可以取消,要求将此属性设置为一个非空值
Exception,Exception,未处理的异常
ExceptionHandled,bool,另一个过滤器,如果有明显的异常处理,则返回true

这里的ExceptionHandler属性要提一下的是,如果这个异常处理完的话,就把它设为true,那么即使有其他的错误处理器捕获到这个异常,也可以通过ExceptionHandler属性判断这个异常是否经过了处理,以免重复处理一个异常错误而引发新的问题。

5.OutputCache过滤器

OutputCache过滤器用作缓存,节省用户访问应用程序的时间和资源,以提高用户体验。

OutputCacheAttribute这个类有以下属性

Duration,int,缓存的时间,以秒为单位,理论上缓存时间可以很长,但实际上当系统资源紧张时,缓存空间还是会被系统收回。
VaryByParam,string,以哪个字段为标识来缓存数据,比如当“ID”字段变化时,需要改变缓存(仍可保留原来的缓存),那么应该设VaryByParam为"ID"。这里你可以设置以下几个值:
* = 任何参数变化时,都改变缓存。
none = 不改变缓存。
以分号“;”为间隔的字段名列表 = 列表中的字段发生变化,则改变缓存。
Location,OutputCacheLocation,缓存数据放在何处。默认是Any,其他值分别是Client,Downstream,Server,None,ServerAndClient
NoStore,bool,用于决定是否阻止敏感信息的二级存储。

例如一个OutputCache过滤器可以这样使用:

[OutputCache(Location= System.Web.UI.OutputCacheLocation.Client,Duration=60)]
        public ActionResult Login()
        {
            return View();
        }

或者有另外一种使用方式——使用配置文件,在<system.web>节点下添加以下设置

<caching>
      <outputCacheSettings>
        <outputCacheProfiles>
          <add name="testCache" location="Client" duration="60"/>
        </outputCacheProfiles>
      </outputCacheSettings>
    </caching>

使用控制的时候就这样

[OutputCache(CacheProfile="testCache")]
        public ActionResult Login()
        {
            return View();
        }

6.自定义过滤器

万一前面介绍的过滤器也满足不了需求,要在行为方法执行返回的前前后后定义自己的处理逻辑的话,这个自定义过滤器就应该能派上用场了。若要自定义一个过滤器,则要继承ActionFilterAttribute类,这个类是一个抽象类,实现了IActionFilter和IResultFilter接口,主要通过重写四个虚方法来达到在行为方法执行和返回的前后注入逻辑

方法

参数

描述

OnActionExecuting

ActionExecutingContext

在行为方法执行前执行

OnActionExecuted

ActionExecutedContext

在行为方法执行后执行

OnResultExecuting

ResultExecutingContext

在行为方法返回前执行

OnResultExecuted

ResultExecutedContext

在行为方法返回后执行

 四个方法执行顺序是OnActionExecuting——>OnActionExecuted——>OnResultExecuting——>OnResultExecuted。

上面四个方法的参数都是继承基ContollorContext类。例如下面定义了一个自定义的过滤器

public class MyCustomerFilterAttribute : ActionFilterAttribute
    {
        public string Message { get; set; }

        public override void OnActionExecuted(ActionExecutedContext filterContext)
        {
            base.OnActionExecuted(filterContext);
            filterContext.HttpContext.Response.Write(string.Format( "<br/> {0} Action finish Execute.....",Message));
        }

        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            CheckMessage(filterContext);
            filterContext.HttpContext.Response.Write(string.Format("<br/> {0} Action start Execute.....", Message));
            base.OnActionExecuting(filterContext);
        }

        public override void OnResultExecuted(ResultExecutedContext filterContext)
        {
            filterContext.HttpContext.Response.Write(string.Format("<br/> {0} Action finish Result.....", Message));
            base.OnResultExecuted(filterContext);
        }

        public override void OnResultExecuting(ResultExecutingContext filterContext)
        {
            filterContext.HttpContext.Response.Write(string.Format("<br/> {0} Action start Execute.....", Message));
            base.OnResultExecuting(filterContext);
        }

        private void CheckMessage(ActionExecutingContext filterContext)
        { 
            if(string.IsNullOrEmpty( Message)||string.IsNullOrWhiteSpace(Message))
                Message = filterContext.Controller.GetType().Name + "'s " + filterContext.ActionDescriptor.ActionName;
        }
    }

使用它的行为方法定义如下:

[MyCustomerFilter]
        public ActionResult CustomerFilterTest()
        {
            Response.Write("<br/>Invking CustomerFilterTest Action");
            return View();
        }

如果控制器和行为方法都使用了过滤器,理论上是显示上面两个结果的有机结合。

但实际不然,因为在定义过滤器的时候还少了一个特性:[AttributeUsage(AttributeTargets.All, AllowMultiple = true)],把这个加在MyCustomerFilterAttribute就行了。

[AttributeUsage(AttributeTargets.All, AllowMultiple = true)]//多次调用
    public class MyCustomerFilterAttribute : ActionFilterAttribute
    {
        //……
    }

同一个过滤器分别用在了控制器和行为方法中,执行同一个方法时都会有先后顺序,如果按默认值(不设Order的情况下),一般的顺序是由最外层到最里层,就是“全局”——>“控制器”——>“行为方法”;而特别的就是错误处理的过滤器,由于异常是由里往外抛的,所以它的顺序刚好也反过来:“行为方法”——>“控制器”——>“全局”。

  既然这里有提到全局的过滤器,那么全局的过滤器是在Global.asax文件里面的RegisterGlobalFilters(GlobalFilterCollection filters)中设置的

public static void RegisterGlobalFilters(GlobalFilterCollection filters)
        {
            filters.Add(new HandleErrorAttribute());
            filters.Add(new MyFilters.MyCustomerFilterAttribute() { Message="Global"});//全局过滤器
        }

  这里它默认也添加了一个错误处理的过滤器来处理整个MVC应用程序所抛出的异常。

转自:http://www.cnblogs.com/xlhblogs/p/3349972.html

原文地址:https://www.cnblogs.com/xsj1989/p/5583951.html