5.3 筛选器/拦截器/过滤器/AOP
5.3.1 关于筛选器
筛选器又名过滤器,拦截器,在 ASP.NET Core 中,可在请求处理管道中特定阶段之前或之后运行代码。筛选器是非常经典的面向切面编程方式,也就是所谓的 AOP 操作。
通俗点说就是可以在控制器 Action 执行前后进行切面操作或返回 Result 结果前后操作。
5.3.2 应用场景
通过自定义筛选器可以实现错误处理,缓存处理,授权处理,日志记录,实现工作单元事务(Uow)等等切面操作,从而使业务逻辑和系统行为逻辑进行分离。
5.3.2.1 筛选器优点
- 易拓展,易集成
- 业务和系统逻辑分离,不干扰业务代码
- 可实现接口多维度控制,如请求参数篡改,返回值篡改,限流,分布式事务支持
- ...
5.3.3 支持拦截应用
Mvc/WebAPI控制器/ActionRazor Pages页面- 框架提供的
动态 WebAPI - 所有请求资源
- 全局异常
5.3.4 筛选器类型
5.3.4.1 接口类型
- 授权筛选器:该筛选器是最先运行,用于确定是否已针对请求为用户授权。 如果请求未获授权,授权筛选器可以让管道短路。
IAuthorizationFilterIAsyncAuthorizationFilterAuthorizeFilter
- 资源筛选器:授权后运行,如果需要是大部分请求管道短路,它将会很有用
IResourceFilterIAsyncResourceFilter
- 操作筛选器:在调用操作方法之前和之后运行代码,可以更改传递的参数,返回结果等,不可在
Razor Pages中使用。IActionFilterIAsyncActionFilter
- 异常筛选器:在向响应正文写入任何内容之前,对未经处理的异常应用全局策略。
IExceptionFilterIAsyncExceptionFilter
- 结果筛选器:在执行操作结果之前和之后立即运行代码,仅当操作方法成功执行时,它们才会运行。 对于必须围绕视图或格式化程序的执行的逻辑,它们很有用。
IResultFilterIAsyncResultFilterIAlwaysRunResultFilter:该接口主要针对所有操作结果运行拦截,也就是即使IResourceFilter设置了Result仍会执行并获取最终的ResultIAsyncAlwaysRunResultFilter
- Razor Pages 筛选器:允许
Razor Pages在运行Razor页面处理程序前后运行代码,和操作筛选器类似,但它们不能应用单个页面处理程序方法。IPageFilterIAsyncPageFilter
5.3.4.2 特性 Attribute 类型
- 授权特性筛选器 (
Attribute+IAsyncAuthorizationFilter):同上接口类型 - 操作特性筛选器 (
ActionFilterAttribute):同上接口类型 - 异常特性筛选器 (
ExceptionFilterAttribute):同上接口类型 - 结果特性筛选器 (
ResultFilterAttribute):同上接口类型 - 服务特性筛选器 (
ServiceFilterAttribute):支持依赖注入的服务筛选器特性 - 类型特性筛选器 (
TypeFilterAttribute):不支持依赖注入但可以传入自定义构造函数参数 - 组合特性筛选器 (
Attribute+ 接口类型方式):可以通过派生自Attribute和 特定接口实现,如Attribute, IActionFilter
筛选器选用技巧
关于选择哪种类型的筛选器有一个小技巧,当你不需要全局筛选器的时候使用特性筛选器,否则使用接口类型筛选器。
另外尽可能的使用带 IAsync 开头的异步筛选器,这样无需分开多个方法,可在一个方法中操作,还能提高吞吐量。
同步异步筛选器
筛选器接口的同步和异步版本任意实现一个,而不是同时实现。
运行时会先查看筛选器是否实现了异步接口,如果是,则调用该接口。 如果不是,则调用同步接口的方法。
如果在一个类中同时实现异步和同步接口,则仅调用异步方法。 使用抽象类(如 ActionFilterAttribute)时,将为每种筛选器类型仅重写同步方法或仅重写异步方法。
5.3.5 筛选器注册
ASP.NET Core 提供了多种筛选器注册方式,通常情况下不同的注册方式执行顺序不同,服务类型注册最先执行,其次是 Mvc Filter 方式,最后是特性方式。相同的方式中又按照注册前后来决定执行顺序,先注册先执行。
同时也提供了 IOrderedFilter 接口重写执行顺序,其 Order 属性值越高的先执行。
5.3.5.1 在 Startup.cs 中注册
最常见的注册筛选器的方式就是在 Startup.cs 中注册,这种方式表示全局注册,应用所有控制器/Action
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
// Mvc 方式注册一,全局执行
services.AddControllersWithViews(options =>
{
options.Filters.Add(new AddHeaderAttribute("GlobalAddHeader", "Result filter added to MvcOptions.Filters")); // 手动创建实例,带构造参数
options.Filters.Add(typeof(MySampleActionFilter)); // 类型 Type 方式
options.Filters.Add(new SampleGlobalActionFilter()); // 手动创建实例,无构造参数
});
// Mvc 方式注册二,全局执行
services.Configure<MvcOptions>(options =>
{
options.Filters.Add<TFilter>();
});
// Mvc 注册方式三,全局执行,Furion 框架提供方式
services.AddMvcFilter<TFilter>();
}
5.3.5.2 特性方式注册
如果筛选器派生自 特性,则可通过特性方式注册,这种方式表示局部注册,只作用于特定的控制器/Action
- 直接贴方式
// 定义结果特性筛选器
public class AddHeaderAttribute : ResultFilterAttribute
{
// ...
}
// 直接贴方式,对于动态 WebAPI 也是一样的
[AddHeader]
public class SampleController : Controller
{
}
- 通过
[ServiceFilter]方式