APS.NET MVC中(如下简称“MVC”)的每个请求,都会分配给相应的控制器和对应的行为方法去处理,而在这些处理的前先后后若是想再加一些额外的逻辑处理。这时候就用到了过滤器。html
MVC支持的过滤器类型有四种,分别是:Authorization(受权),Action(行为),Result(结果)和Exception(异常)。以下表,web
过滤器类型缓存 |
接口服务器 |
描述ide |
Authorizationthis |
IAuthorizationFilterspa |
此类型(或过滤器)用于限制进入控制器或控制器的某个行为方法code |
Exceptionorm |
IExceptionFilterhtm |
用于指定一个行为,这个被指定的行为处理某个行为方法或某个控制器里面抛出的异常 |
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这个类,这个类里面有两个方法是要重写的
这里就定义了一个比较骑呢的受权处理器,当请求的时候恰好是偶数分钟的,就经过能够得到受权,反之则不经过。当受权失败的时候,就会跳转到登录页面了。
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=" background-color:Orange">@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"。这里你能够设置如下几个值: |
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