MVC过滤器详解

 

APS.NET MVC中(以下简称“MVC”)的每一个请求,都会分配给相应的控制器和对应的行为方法去处理,而在这些处理的前前后后如果想再加一些额外的逻辑处理。这时候就用到了过滤器。

  MVC支持的过滤器类型有四种,分别是:Authorization(授权),Action(行为),Result(结果)和Exception(异常)。如下表,

过滤器类型

接口

描述

Authorization

IAuthorizationFilter

此类型(或过滤器)用于限制进入控制器或控制器的某个行为方法

Exception

IExceptionFilter

用于指定一个行为,这个被指定的行为处理某个行为方法或某个控制器里面抛出的异常

Action

IActionFilter

用于进入行为之前或之后的处理

Result

IResultFilter

用于返回结果的之前或之后的处理

  但是默认实现它们的过滤器只有三种,分别是Authorize(授权),ActionFilter,HandleError(错误处理);各种信息如下表所示

过滤器

类名

实现接口

描述

ActionFilter

AuthorizeAttribute

IAuthorizationFilter

此类型(或过滤器)用于限制进入控制器或控制器的某个行为方法

HandleError

HandleErrorAttribute

IExceptionFilter

用于指定一个行为,这个被指定的行为处理某个行为方法或某个控制器里面抛出的异常

自定义

ActionFilterAttribute

IActionFilter和IResultFilter

用于进入行为之前或之后的处理或返回结果的之前或之后的处理

  下面介绍的过滤器中,除了上面这几种外,还多加一种过滤器OutputCache

1           授权过滤器Authorize

1.1          默认Authorize使用

  现在在网上无论是要求身份验证的地方多得是,发邮件,买东西,有时候就算吐个槽都要提示登录的。这里的某些操作,就是要经过验证授权才被允许。在MVC中可以利用Authorize来实现。例如一个简单的修改密码操作

        [Authorize]
public ActionResult ChangePassword()
{
return View();
}

它需要用户通过了授权才能进入到这个行为方法里面,否则硬去请求那个页面的话,只会得到这个结果

如果要通过验证,通过调用FormsAuthentication.SetAuthCookie方法来获得授权,登陆的页面如下

@model FilterTest.Models.LogInModel
@{
Layout = null;
} <!DOCTYPE html> <html>
<head>
<title>Login</title>
</head>
<body>
<div>
@using( Html.BeginForm()){
<div>
ID:@Html.TextBoxFor(m=>m.UserName)
<br />
Password:@Html.PasswordFor(m => m.Password)
<br />
<input type="submit" value="login" />
</div>
}
</div>
</body>
</html>

行为方法如下

        [HttpPost]//这里用了谓词过滤器,只处理POST的请求
public ActionResult Login(LogInModel login)
{
if (login.UserName == "admin" && login.Password == "123456")
{
FormsAuthentication.SetAuthCookie(login.UserName, false);
return Redirect("/Customer/ChangePassword");
} return View();
}

当然有登录也要有注销,因为注销是在登陆之后发生的,没登陆成功也就没有注销,所以注销的行为方法也要加上Authorize过滤器,注销调用的是FormsAuthentication.SignOut方法,代码如下

        [Authorize]
public ActionResult LogOut()
{
FormsAuthentication.SignOut();
return Redirect("/Customer/Login");
}

1.2          自定义授权

我们不一定要用MVC默认的Authorize授权验证规则,规则可以自己来定,自定义授权过滤器可以继承AuthorizeAttribute这个类,这个类里面有两个方法是要重写的

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

这里就定义了一个比较骑呢的授权处理器,当请求的时候刚好是偶数分钟的,就通过可以获得授权,反之则不通过。当授权失败的时候,就会跳转到登陆页面了。

    public class MyAuthorizeAttribute:AuthorizeAttribute
{ protected override bool AuthorizeCore(HttpContextBase httpContext)
{
//return base.AuthorizeCore(httpContext);
return DateTime.Now.Minute % 2 == 0
} protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
filterContext.HttpContext.Response.Redirect("/Customer/Login"); //base.HandleUnauthorizedRequest(filterContext);
}
}

然后用到一个行为方法上,

        [MyAuthorize]
public ActionResult ShowDetail()
{
return View();
}

每当偶数分钟的时候就可以访问得到这个ShowDetail的视图,否则就会跳到了登陆页面了。

2           处理错误过滤器HandleError

2.1          默认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

这个Order属性其实不只这个HandleError过滤器有,其优先级规则跟其他过滤器的都是一样。

下面则故意弄一个会抛异常的行为方法

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

光是这样还不够,还要到web.config文件中的<system.web>一节中添加以下代码

<customErrors mode="On" />

因为默认的开发模式中它是关闭的,要等到部署到服务器上面才会开启,让异常信息比较友好的用一个视图展现。

  像这里访问ThrowErrorLogin视图时,由于抛出了一次,就转到了一个特定的视图

  在这里看到的异常视图是这样的,除了用这个建项目时默认生成的异常视图之外,我们还可以自己定义异常视图,视图里面要用到的异常信息,可以通过@Model获取,它是一个ExceptionInfo类型的实例,例如这里建了一个异常视图如下

@{
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=" padding: 0px; color: rgb(0, 0, 255); line-height: 1.5 !important;">>@Model.Exception.StackTrace</pre>
</div>
</body>
</html>

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

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

2.2          自定义错误异常处理

  这里的错误处理过滤器也可以自己来定义,做法是继承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("5洗ten No Problem<br/>" +
filterContext.Exception.ToString());
}
}

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

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

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

3           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();
}

4           自定义过滤器

  万一前面介绍的过滤器也满足不了需求,要在行为方法执行返回的前前后后定义自己的处理逻辑的话,这个自定义过滤器就应该能派上用场了。若要自定义一个过滤器,则要继承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/HopeGi/p/3342083.html#commentform

MVC过滤器详解的更多相关文章

  1. ASP.NET MVC 过滤器详解

    http://www.fwqtg.net/asp-net-mvc-%E8%BF%87%E6%BB%A4%E5%99%A8%E8%AF%A6%E8%A7%A3.html 我经历了过滤器的苦难,我想到了还 ...

  2. MVC过滤器详解和示例

    原文  http://blog.csdn.net/ankeyuan/article/details/29624005 MVC过滤器一共分为四个:ActionFilter(方法过滤器),ResultFi ...

  3. MVC过滤器详解 面向切面编程(AOP)

    面向切面编程:Aspect Oriented Programming(AOP),面向切面编程,是一个比较热门的话题.AOP主要实现的目的是针对业务处理过程中的切面进行提取,它所面对的是处理过程中的某个 ...

  4. Asp.Net MVC学习总结之过滤器详解(转载)

    来源:http://www.php.cn/csharp-article-359736.html   一.过滤器简介 1.1.理解什么是过滤器 1.过滤器(Filters)就是向请求处理管道中注入额外的 ...

  5. springmvc进阶(5):mvc:default-servlet-handler详解

    我们在配置dispatchServlet时配置<url-pattern>/</url-pattern>拦截所有请求,这时候dispatchServlet完全取代了default ...

  6. Wireshark过滤器详解

    Wireshark过滤器详解 1.Wireshark主要提供两种主要的过滤器 捕获过滤器:当进行数据包捕获时,只有那些满足给定的包含/排除表达式的数据包会被捕获 显示过滤器:该过滤器根据指定的表达式用 ...

  7. angular-ngSanitize模块-linky过滤器详解

    本篇主要讲解angular中的linky这个过滤器.此过滤器依赖于ngSanitize模块. linky能找出文本中的链接,然后把它转换成html链接.什么意思,就是说,一段文本里有一个链接,但是这个 ...

  8. Spring MVC配置详解(3)

    一.Spring MVC环境搭建:(Spring 2.5.6 + Hibernate 3.2.0) 1. jar包引入 Spring 2.5.6:spring.jar.spring-webmvc.ja ...

  9. Asp.Net Mvc 控制器详解

    理解控制器 控制器的角色 (1)中转作用:控制器通过前面的学习大家应该知道它是一个承上启下的作用,根据用户输入,执行响应行为(动 作方法),同时在行为中调用模型的业务逻辑,返回给用户结果(视图). ( ...

随机推荐

  1. CentOS MySQL 配置

    问题: MySQL安装后root用户无法连接,提示 ERROR 1045 (28000): Access denied for user ’root’@’localhost’ (using passw ...

  2. .NET文件跨服务器上传下载

    环境说明:两台服务器服务器为A,服务器为B,服务器B为文件服务器 1.在A和B上创建用户docshareuser,用户名和密码保持一致 2.B服务器上设置附件文件夹Attachments共享,添加用户 ...

  3. go 语言中常用的包

    来自学习go语言.pdf 译者刑星 ==== fmt 包fmt实现了格式化IO函数,这与c的printf和scanf类似,格式化短语派生于c %v 默认格式的值.当打印结构时,加号(%+v)会增加字段 ...

  4. STM32F4读写内部FLASH【使用库函数】

    STM32F4Discovery开发帮使用的STM32F407VGT6芯片,内部FLASH有1M之多.平时写的代码,烧写完之后还有大量的剩余.有效利用这剩余的FLASH能存储不少数据.因此研究了一下S ...

  5. docker使用阿里云Docker镜像库加速

    官方镜像下载实在是慢,于是开通了阿里云开发者帐号, 官方帮助 阿里云Docker镜像库 阿里云容器Hub服务:http://dev.aliyun.com/search.html 来自云端的容器Hub服 ...

  6. Django进阶篇(二)

    中间件 解析 django 中的中间件(middleware),在django中,中间件其实就是一个类,在请求到来和结束后, django会根据自己的规则在合适的时机执行中间件中相应的方法. 在dja ...

  7. 开源免费的天气预报接口API以及全国所有地区代码(国家气象局提供)

    天气预报一直是各大网站的一个基本功能,最近小编也想在网站上弄一个,得瑟一下,在网络搜索了很久,终于找到了开源免费的天气预报接口API以及全国所有地区代码(国家气象局提供),具体如下: 国家气象局提供的 ...

  8. cocos2dx day 1

    原文:http://www.cocos2d-x.org/programmersguide/2/index.html 一.Basic Concepts 1.director 2.scene 2.1 sc ...

  9. jquery 中post 、get的同步问题

    jquery 中post .get的同步问题 解决方法1: 在全局设置: $.ajaxSetup({ async : false }); 然后再使用post或get方法 $.get("reg ...

  10. oracle大表添加字段default经验分享

    当oracle单表数据量上亿时,对表进行alter table aa add column_1 varchar2(2) defalut 'Y';时,效率及安全性是必须考虑的因素. 本帖以2亿的数据表a ...