asp.net core系列 68 Filter管道过滤器
一.概述
本篇详细了解一下asp.net core filters,filter叫"筛选器"也叫"过滤器",是请求处理管道中的特定阶段之前或之后运行代码。filter用于处理横切关注点。 横切关注点的示例包括:错误处理、缓存、配置、授权和日志记录。 filter可以避免重复代码,通过attribute特性来实现filter过滤。filter适应于 razor pages, api controllers, mvc controllers。filter基类是ifiltermetadata 接口,该接口只是用来标记是一个filter过滤器。
前段时间在项目中实现了iasyncauthorizationfilter接口对用户访问controller或action进行了授权,在onauthorizationasync方法中使用context.result可使管道短道。iasyncauthorizationfilter是属于授权过滤器中的一种。勿在授权过滤器内抛出异常,这是因为所抛出的异常不会被处理。下面是简要的实现授权代码:
[attributeusage(attributetargets.class | attributetargets.method)] public class permissionfilter : attribute,iasyncauthorizationfilter { public task onauthorizationasync(authorizationfiltercontext context) { iidentity user = context.httpcontext.user.identity; if (!user.isauthenticated) { //跳转到登录页 context.result = new localredirectresult(url); return task.completedtask; } //根据当前用户,判断当前访问的action,没有权限时返回403错误 context.result = new forbidresult(); return task.completedtask; } }
在官方文档中说到:"自定义授权筛选器filter需要自定义授权框架, 建议配置授权策略或编写自定义授权策略,而不是编写自定义filter筛选器"。
这里的意思是说,如果在项目中不使用asp.net core自带的identity,那么需要自定义授权框架,也就是需要自己建立一套用户权限表。 如果使用了identity建议配置授权策略或编写自定义授权策略。如果不用identity自己建立用户权限表,那么就可以编写自定义filter筛选器。我在项目开发中是自己建立了用户权限表没有用identity。因为使用identity表还需要扩展字段,而且与ef core结合紧密,如果不使用ef core需要重写访问identity表的实现。
下面是identity与ef core相关的代码:
services.addidentity<applicationuser, identityrole>() .addentityframeworkstores<applicationdbcontext>() .adddefaulttokenproviders(); -- tcontext必须是dbcontext类型 public static identitybuilder addentityframeworkstores<tcontext>(this identitybuilder builder) where tcontext : dbcontext
二.filter 筛选器类型
authorization filters 授权筛选器
resource filters 资源筛选器
action filters 操作筛选器 (razor pages 中使用 ipagefilter 和 iasyncpagefilter)
exception filters 异常筛选器
result filters 结果筛选器
每种filter 类型都在filter 管道中的不同阶段执行,当用户请求进来时,经过filter管道,执行filter的阶段顺序如下所示:
上面每种filter 类型都有自己的接口,都同时支持同步和异步实现,上面的授权示例就是一个异步实现授权筛选器iasyncauthorizationfilter。filter 接口或直接或间接实现了ifiltermetadata接口,ifiltermetadata接口只是用来标记是一个filter 。
三.filter筛选器作用域
(1) 将 attribute特性应用在 action上。
(2) 将 attribute特性应用在 controller上。
(3) 全局筛选器应用在controller和action上
下面使用全局筛选器,使用mvcoptions.filters 集合,添加三个筛选器,如下面的代码所示:
public void configureservices(iservicecollection services) { services.addmvc(options => { options.filters.add(new addheaderattribute("globaladdheader", "result filter added to mvcoptions.filters")); // an instance options.filters.add(typeof(mysampleactionfilter)); // by type options.filters.add(new sampleglobalactionfilter()); // an instance }).setcompatibilityversion(compatibilityversion.version_2_2); }
//实现了内置筛选器属性 public class addheaderattribute : resultfilterattribute //实现了操作筛选器 public class mysampleactionfilter : iactionfilter //实现了操作筛选器 public class sampleglobalactionfilter : iactionfilter
四.内置筛选器attribute属性
下面都是filter内置的属性类,需要去实现这些抽象属性类。
actionfilterattribute
exceptionfilterattribute
resultfilterattribute
formatfilterattribute
servicefilterattribute
typefilterattribute
下面一个示例是为响应添加标头,开发人员来实现resultfilterattribute抽象类:
public class addheaderattribute : resultfilterattribute { private readonly string _name; private readonly string _value; public addheaderattribute(string name, string value) { _name = name; _value = value; } public override void onresultexecuting(resultexecutingcontext context) { context.httpcontext.response.headers.add( _name, new string[] { _value }); base.onresultexecuting(context); } }
通过使用属性,筛选器可接收参数,将 addheaderattribute
添加到控制器或操作方法,并指定 http 标头的名称和值,如下所示:
[addheader("author", "steve smith @ardalis")] public iactionresult hello(string name) { return content($"hello {name}"); }
五.filter三种依赖关系注入
(1)servicefilterattribute
(2)typefilterattribute
(3)在属性上实现 ifilterfactory。
5.1 servicefilterattribute演示
下面是在 configureservices 中注册服务筛选器实现类型,内置的servicefilterattribute会从di 检索筛选器实例。
public class addheaderresultservicefilter : iresultfilter { private ilogger _logger; public addheaderresultservicefilter(iloggerfactory loggerfactory) { _logger = loggerfactory.createlogger<addheaderresultservicefilter>(); } public void onresultexecuting(resultexecutingcontext context) { var headername = "onresultexecuting"; context.httpcontext.response.headers.add( headername, new string[] { "resultexecutingsuccessfully" }); _logger.loginformation($"header added: {headername}"); } public void onresultexecuted(resultexecutedcontext context) { // can't add to headers here because response has started. } }
在以下代码中,addheaderresultservicefilter 将添加到 di 容器中:
services.addscoped<addheaderresultservicefilter>();
在以下代码中,通过servicefilter 属性,将从 di 中检索 addheaderresultservicefilter 筛选器的实例:
[servicefilter(typeof(addheaderresultservicefilter))] public iactionresult index() { return view(); }
六. 各种筛选器介绍
6.1 authorization filters
是筛选器管道中第一个运行的筛选器。是控制对action方法的访问。
在action之前执行的方法,没有在action之后执行的方法。
注意:不要在授权筛选器中引发异常
场景:
如果使用identity,可用配置授权策略或编写自定义授权策略。详情查看identity部分。
如果不使用identity,可编写自定义筛选器。
6.2 resource filters
实现 iresourcefilter 或 iasyncresourcefilter 接口。
它执行会覆盖筛选器管道的绝大部分。
它在授权筛选器之后运行。
场景:
可以防止模型绑定访问表单数据。
用于上传大型文件,以防止表单数据被读入内存。
6.3 action filters
实现 iactionfilter 或 iasyncactionfilter 接口。
它围绕着action方法的执行。
它方法中有个重要属性actionarguments ,用于读取action的输入参数。
场景:
可以在该接口的onactionexecuting方法中进行验证模型状态(modelstate.isvalid),如果状态无效,则返回错误(这个场景很有用)。
6.4 exception filters
实现 iexceptionfilter 或 iasyncexceptionfilter。
它没有之前和之后的事件,
可实现该接口的 onexception 或 onexceptionasync方法。
处理 razor 页面或控制器创建、模型绑定、操作筛选器或操作方法中发生的未经处理的异常。
若要处理异常(不再throw),请将 exceptionhandled 属性设置为 true。
场景:
实现常见的错误处理策略。
非常适合捕获发生在action中的异常。
6.5 result filters
实现 iresultfilter 或 iasyncresultfilter 或 ialwaysrunresultfilter 或 iasyncalwaysrunresultfilter
它执行围绕着action结果的执行。当异常筛选器处理异常时,不执行结果筛选器。
如果在 iresultfilter.onresultexecuting 中引发异常,则会导致:
(1) 阻止action结果和后续筛选器的执行。
(2) 结果被视为失败。
更详细的资料参考官网文档,后续在实际项目中应用到的筛选器,将会再本篇继续补上。
参考资料:
上一篇: .NET MVC5简介(六)HttpHandler
下一篇: 可乐的危害有几种,现在知道还不晚!