ASP.NET MVC 过滤器
APS.NET MVC中(以下简称“MVC”)的每一个请求,都会分配给相应的控制器和对应的行为方法去处理,而在这些处理的前前后后如果想再加一些额外的逻辑处理。这时候就用到了过滤器。
MVC的过滤器类型
过滤器类型 |
接口 |
描述 |
Authorization |
IAuthorizationFilter |
此类型(或过滤器)用于限制进入控制器或控制器的某个行为方法 |
Exception |
IExceptionFilter |
用于指定一个行为,这个被指定的行为处理某个行为方法或某个控制器里面抛出的异常 |
Action |
IActionFilter |
用于进入行为之前或之后的处理 |
Result |
IResultFilter |
用于返回结果的之前或之后的处理 |
过滤器类型 |
接口 |
默认实现 |
描述 |
Authorization |
IAuthorizationFilter |
AuthorizationAttribute |
最先运行 |
Action |
IActionFilter |
ActionFilterAttribute |
在动作方法前后运行 |
Result |
IResultFilter |
ActionResultAttribute |
在动作结果被执行前后 |
Exception |
IExceptionFilter |
HandlerErrorAttribute |
仅在过滤器、动作发生异常时 |
但是默认实现它们的过滤器只有三种,分别是Authorize(授权),ActionFilter,HandleError(错误处理)
过滤器 |
类名 |
实现接口 |
描述 |
ActionFilter |
AuthorizeAttribute |
IAuthorizationFilter |
此类型(或过滤器)用于限制进入控制器或控制器的某个行为方法 |
HandleError |
HandleErrorAttribute |
IExceptionFilter |
用于指定一个行为,这个被指定的行为处理某个行为方法或某个控制器里面抛出的异常 |
自定义 |
ActionFilterAttribute |
IActionFilter和IResultFilter |
用于进入行为之前或之后的处理或返回结果的之前或之后的处理 |
一:Authorize(授权过滤器)
(1)默认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"); }
(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的视图了,否则就会调到了登陆页面了
二:处理错误过滤器HandleError
(1) 默认HandleError使用
HandleErroe的属性如下
属性名称 |
类型 |
描述 |
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" />
四:自定义过滤器
万一前面介绍的过滤器也满足不了需求,要在行为方法执行返回的前前后后定义自己的处理逻辑的话,这个自定义过滤器就应该能派上用场了。若要自定义一个过滤器,则要继承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; } }
(1)使用它的行为方法定义
[MyCustomerFilter] public ActionResult CustomerFilterTest() { Response.Write("<br/>Invking CustomerFilterTest Action"); return View(); }
执行结果如下
验证了执行顺序
(2) 当控制器也使用上这个过滤器时,而行为方法不使用时,结果
这个也验证了结果顺序
(3)如果控制器和行为方法都使用了过滤器,理论上是显示上面两个结果的结合,但是实际上不是,因为在定义过滤器的时候还少了
一个特性:[AttributeUsage(AttributeTargets.All, AllowMultiple = true)],把这个加上
[AttributeUsage(AttributeTargets.All, AllowMultiple = true)]//多次调用 public class MyCustomerFilterAttribute : ActionFilterAttribute { …… }
结果执行顺序
可以看出,同一个过滤器分别用在了控制器和行为方法中,执行同一个方法都会有先后顺序,如果按默认值,一般顺序都是由最外层到最里层,就是"全局"--控制器--行为方法,而错误处理的过滤器,由于异常是由里往外抛,行为方法---控制器---全局。
全局的过滤器在Global.asax文件里面的RegisterGlobalFilters(GlobalFilterCollection filters)中设置的
public static void RegisterGlobalFilters(GlobalFilterCollection filters) { filters.Add(new HandleErrorAttribute()); filters.Add(new MyFilters.MyCustomerFilterAttribute() { Message="Global"});//全局过滤器 }
转自 :http://www.cnblogs.com/HopeGi/p/3342083.html#commentform