Asp.Net MVC学习总结之过滤器详解
一、过滤器简介
1.1、理解什么是过滤器
1、过滤器(filters)就是向请求处理管道中注入额外的逻辑。提供了一个简单而优雅的方式来实现横切关注点。
2、所谓的过滤器(filters),mvc框架里面的过滤器完全不同于asp.net平台里面的request.filters和response.filter对象,它们主要是实现请求和响应流的传输。通常我们所说的过滤器是指mvc框架里面的过滤器。
3、过滤器可以注入一些代码逻辑到请求处理管道中,是基于c#的attribute的实现。当负责调用action的类controlleractioninvoker在调用执行action的时候会检查action上面的attribute并查看这些attribute是否实现了指定的接口,以便进行额外的代码注入处理
1.2、理解为什么要使用过滤器
假设你做了一个小项目,其中某个功能是操作管理用户信息模块,有这样一个需求,对用户信息管理必须是已通过认证的用户才能操作,我们可以在每一个action方法里面检查认证请求,如下所示:
using mvcfilterdmo.core; using system; using system.collections.generic; using system.linq; using system.web; using system.web.mvc; using system.web.security; namespace mvcfilterdmo.controllers { public class homecontroller : controller { public actionresult index() { if (!request.isauthenticated) { formsauthentication.redirecttologinpage(); } //操作部分... return view(); } public actionresult insert() { if (!request.isauthenticated) { formsauthentication.redirecttologinpage(); } //操作部分... return view(); } public actionresult update() { if (!request.isauthenticated) { formsauthentication.redirecttologinpage(); } //操作部分... return view(); } public actionresult delete() { if (!request.isauthenticated) { formsauthentication.redirecttologinpage(); } //操作部分... return view(); } //其他action操作方法 //... } }
通过上面的代码,可以发现使用这种方式检查请求认证有许多重复的地方,这也就是为什么要使用过滤器的原因,使用过滤器可以实现相同的效果。如下所示:
using mvcfilterdmo.core; using system; using system.collections.generic; using system.linq; using system.web; using system.web.mvc; using system.web.security; namespace mvcfilterdmo.controllers { [authorize] public class homecontroller : controller { public actionresult index() { //操作部分... return view(); } public actionresult insert() { //操作部分... return view(); } public actionresult edit() { //操作部分... return view(); } public actionresult delete() { //操作部分... return view(); } //其他action操作方法 //... } }
过滤器是.net里面的特性(attributes),它提供了添加到请求处理管道的额外方法。这里使用authorize过滤器可以实现同样的效果,不过代码就显然比之前更加简洁优雅。
二、过滤器的使用
2.1、基本类型的过滤器
过滤器实现的机制:在mvc框架调用一个action之前,它会检查方法的定义中是否实现了特性(attributes),如果实现的话,那么在请求处理管道适当的位置,该特性定义的方法会被调用。
actionfilterattribute类既实现了iactionfilter接口,也实现iresultfilter接口。这是一个抽象类,它要求你必须提供一个实现。authorizeattribute和handleerrorattribute类,则包含了一些有用的特性,并且可以不必创建派生类进行使用。
2.2、过滤器的应用、应用方式以及执行顺序
应用: 过滤器可以被应用到控制器上也可以用到action方法上,应用到控制上时,表示所有的action方法都有了这个过滤器,并且可以混合使用,或多次使用,如下所示:
[a] //表示所有的action方法都会应用a过滤器 public class democontroller:controller { [b]//b,c过滤器只作用于此action方法,但它也会有a过滤器的应用效果 [c] public actionresult index() { //操作部分... return view(); } }
应用方式:特性的方式,如上面代码所示。
执行顺序:相同类型过滤器,执行顺序靠近方法的先执行,不同类型的过滤器一般执行顺序为【authorize--->action--->actionresult】至于异常过滤器不分先后,只要抛出异常时就会执行异常过滤器。如果要调整执行顺序,可以通过调整order方法值大小来控制执行顺序,值越小,越先执行。下图是action/result过滤器应用的执行顺序图
(1)、相同类型过滤器应用示例:两个自定义action过滤器myfirstfilter,mythreefilter应用到同一个action方法index上。
three控制器代码如下:
myfirstfilter 代码如下:
mythreefilter代码如下:
运行结果如下:
(2)、不同类型过滤器应用示例:有一个自定义action过滤器myfirstfilter,有一个自定义result过滤器mysecondfilter,应用到同一个action方法index上。
three控制器代码如下:
myfirstfilter 代码如下:
mysecondfilter代码如下:
运行结果如下:
看完上面的解释,可能你现在对这些过滤器的执行顺序,以及如何自定义过滤器还不明白,不要紧,下面我们会逐一介绍这几个基本的过滤器的使用,以及如何自定义过滤器。
2.3、使用授权过滤器
所有实现了iauthorizationfilter接口的都可以称之为授权过滤器:其定义如下:
public interface iauthorizationfilter { void onauthorization(authorizationcontext filtercontext); }
由于mvc框架系统自带的authorizeattribute实现有一些突出的功能,而这种牵涉到安全的代码一定要谨慎的编写,所以一般我们不会直接实现这个接口,而是去继承authorizeattribute这个类,并重写其authorizecore方法,签名为: bool authorizecore(httpcontextbase httpcontext) 而处理授权失败的时候,可以重写其handleunauthorizedrequest方法,其签名为: void handleunauthorizedrequest(authorizationcontext context) 。注意:验证与授权是两回事,验证发生在授权之前。
默认的授权过滤器已经有了验证的功能,其验证的机理是利用asp.net平台自带的验证机制,如表单验证和windows验证。除了验证功能,它本身还有授权的功能。授权过滤器是所有过滤器中最早运行的。
经过route到达了控制器的时候,在调用action之前,mvc框架会检测在相关的action上是否有授权过滤器,如果有会调用onauthorization方法,如果此方法批准了请求,才会调用相应的action。
使用授权过滤器几种情况如下:
1.直接在action上或者控制器上加authorize,表示启用了验证,但不牵涉到授权。
2.添加authorize(users=“a,b”)],表示启用了验证,并且也启用了授权,只有a或者b用户能访问此控制器。
3.当添加authorize(roles=“admin,member”)]时的步骤如下:
---利用asp.net自带的角色提供者,或者实现自己的角色提供者,实现自己的角色提供者时,只需要集成roleprovider类型,并实现其中的所有方法或部分方法,最好实现所有方法。
---在web程序的根目录的web.config文件中配置角色管理者。
---在适当的action中利用roles类型来访问自己创建的roleprovider中的相关方法。
使用内置的授权过滤器
mvc框架内置的授权过滤器authorizeattribute,它允许我们使用这个类的两个公共属性来指定授权策略,如下所示:
users和roles两者是并且的关系,例如users=“a,b,c”,roles=“admin”,表示用户是a,b,c 其中一个并且是admin角色才能访问。
创建自定义的授权过滤器
方式一:直接实现iauthorizationfilter接口,但不推荐这样做,因为牵涉到安全方面的代码。
方式二:继承authorizeattribute这个类,并重写其authorizecore方法,签名为: bool authorizecore(httpcontextbase httpcontext),代码如下所示:
public class myauthorizeattribute : authorizeattribute { private string[] allowedusers; public myauthorizeattribute(params string[] users) { allowedusers = new string[] { "admin", "user1", "xf" }; } protected override bool authorizecore(httpcontextbase httpcontext) { return httpcontext.request.isauthenticated &&allowedusers.contains(httpcontext.user.identity.name, stringcomparer.invariantcultureignorecase); } }
2.4、使用动作过滤器
动作过滤器是可以以用于任何目的的多用途过滤器,创建自定义动作过滤器需要实现iactionfilter接口,该接口代码如下所示:
该接口定义了两个方法,mvc框架在调用动作方法之前,会调用onactionexecting方法。在调用动作方法之后,则会调用onactionexecuted方法。
实现onactionexecting方法
参数actionexecutingcontext对象继承于controllercontext,其中的2个属性:
actiondescriptor:提供了关于action方法的相关信息
result:类型为actionresult,通过给这个属性设置一个非null的值就可以取消这个请求。
我们可以用过滤器来取消一个请求,通过设置result属性即可。代码如下所示:
public class myactionfilterattribute : filterattribute, iactionfilter { public void onactionexecuting(actionexecutingcontext filtercontext) { if(filtercontext.httpcontext.request.islocal) { filtercontext.result = new httpnotfoundresult(); } } public void onactionexecuted(actionexecutedcontext filtercontext) { //未做实现 } }
这个例子通过用onactionexecuting方法检查请求是否来自本地机器,如果是,编队用户返回一个“404”未找到的响应。运行结果如下图:
实现onactionexecuted方法
我们也可以通过onactionexecuted方法来执行一些跨越动作方法的任务,下面这个例子是计算动作方法运行的时间,代码如下:
public class myactionfilterattribute : filterattribute, iactionfilter { private stopwatch timer; public void onactionexecuting(actionexecutingcontext filtercontext) { timer = stopwatch.startnew(); } public void onactionexecuted(actionexecutedcontext filtercontext) { timer.stop(); if (filtercontext.exception == null) { filtercontext.httpcontext.response.write( string.format("动作方法延迟的时间: {0}", timer.elapsed.totalseconds)); } } } }
我们将自定义的动作过滤器myactionfilter应用到homecontroller的index方法上,运行结果如下:
2.5、使用结果过滤器
结果过滤器是多用途的过滤器,他会对动作方法所产生结果进行操作,结果过滤器实现iresultfilter接口,创建自定义结果过滤器需要现iresultfilter接口,该接口代码如下所示:
当结果过滤器运用于一个动作方法时,会在动作方法返回动作结果之前,调用onresultexecuting方法,在返回动作结果之后,会调用onresultexecuted方法。下面这个例子是计算动作方法返回结果运行的时间,代码如下:
public class myresultfilterattribute : filterattribute, iresultfilter { private stopwatch timer; public void onresultexecuting(resultexecutingcontext filtercontext) { timer = stopwatch.startnew(); } public void onresultexecuted(resultexecutedcontext filtercontext) { timer.stop(); filtercontext.httpcontext.response.write(string.format("结果执行延迟时间: {0}", timer.elapsed.totalseconds)); } }
我们将自定义的结果过滤器myresultfilter应用到homecontroller的index方法上,运行结果如下:
需要注意的是:动作过滤器是运行在页面输出之前,结果过滤器是运行在页面输出之后。
2.6、使用异常过滤器
异常过滤器只有在调用一个动作方法而抛出未处理的异常才会运行,这种异常来自以下位置:
a、另一种过滤器(授权、动作、或结果过滤器)。
b、动作方法本身。
c、当动作结果被执行时。
使用内置的异常过滤器
handleerrorattribute(处理程序错误特性),它是mvc内嵌的异常过滤器,有以下3个重要的属性:
1.exceptiontype:类型为type,表示希望被此过滤器处理的异常类型,包括其子类型,默认值为system.exception
2.view:类型为string,表示此过滤器呈递的视图页面,默认值为error
3.master:呈递的视图页的母板页,如果不指定,视图会用其默认的母版页
内嵌的handleerrorexception只有在配置文件web.config中配置的customerror 的mode设置为on的时候才生效(其默认模式为remoteonly),如下图所示:
此过滤器还会给视图传递一个handleerrorinfo类型的对象给视图,以便视图可以显示一些额外的关于错误的信息。下面是使用异常过滤器的示例。
应用到index动作方法上:
在views/shared文件夹下添加一个显示异常信息的视图页specialerror.cshtml,页面代码如下:
@model handleerrorinfo <!doctype html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>specialerror</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> </div> </body> </html>
运行结果如下:
创建自定义的异常过滤器
如果我们对异常过滤器有特殊的需求,可以通过自定义的异常过滤器来完成,创建自定义异常过滤器必须实现iexceptionfilter接口,该接口代码如下:
当一个未知处理异常发生时,onexception方法会被调用。该方法的传递一个exceptioncontext对象,派生于controllercontext类,定义了一些额外的过滤器专有属性如下表所示:
抛出的异常通过exception属性是可以访问的。通过把exceptionhandled属性设置为true,一个异常过滤器可以报告它已经处理了该异常,应用于一个动作的所有异常过滤器都会被调用。
需要注意的是:如果一个动作方法的所有异常过滤器均为把exceptionhandled属性设置为true,mvc框架将使用默认的asp.net异常处理程序。
result属性有异常过滤器使用,以告诉mvc框架要做什么,异常过滤器的两个主要应用是记录该异常到日志,并把适当的消息显示给用户。下面的代码将演示通过创建一个自定义的异常过滤器,当一个特定的钟类的未处理异常出现时,把该用户重定向到一个指定的错误页面。
public class myexectionattribute:filterattribute,iexceptionfilter { public void onexception(exceptioncontext filtercontext) { if(!filtercontext.exceptionhandled&& filtercontext.exception is nullreferenceexception) { filtercontext.result = new redirectresult("~/content/specialerrorpage.html"); filtercontext.exceptionhandled = true; } } }
然后在项目根目录添加一个名为content的文件夹,在该文件夹下创建specierrorpage.html文件,当异常被处理时,将以这个错误页面显示个用户。该页面代码如下:
<!doctype html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="content-type" content="text/html; charset=utf-8"/> <title></title> </head> <body> <h1>sorry</h1> <p>this is a excetption test</p> there was anullreferenceexception while renderinghome's index action </body> </html>
在控制器中应用myexection异常过滤器,并主动让其抛出一个空引用异常,以便测试。
public class homecontroller : controller { [myexection] public actionresult index() { throw new nullreferenceexception(); } }
运行结果如下:
总结:本文章简单总结了对过滤器的理解以及如何使用mvc框架内置基本的过滤器和如何自定义过滤器及应用。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
上一篇: 电脑不能联网360随身wifi可以用吗
下一篇: CAD图纸不能复制粘贴该怎么办?