ASP.NET Core 2 学习笔记(十四)Filters
Filter是延续ASP.NET MVC的产物,同样保留了五种的Filter,分别是Authorization Filter、Resource Filter、Action Filter、Exception Filter及Result Filter。
通过不同的Filter可以有效处理封包进出的加工,本篇将介绍ASP.NET Core的五种Filter运作方式。
Filter 介绍
Filter的作用是在Action 执行前或执行后做一些加工处理。
某种程度来看,会跟Middleware很像,但执行的顺序略有不同,用对Filter不仅可以减少代码,还可以提高执行效率。
ASP.NET Core 有以下五种Filter 可以使用:
-
Authorization Filter
Authorization是五种Filter中优先级最高的,通常用于验证Request合不合法,不合法后面就直接跳过。 -
Resource Filter
Resource是第二优先,会在Authorization之后,Model Binding之前执行。通常会是需要对Model加工处理才用。 -
Action Filter
最常使用的Filter,封包进出都会经过它,使用上没什么需要特别注意的。跟Resource Filter很类似,但并不会经过Model Binding。 -
Exception Filter
异常处理的Filter。 -
Result Filter
当Action完成后,最终会经过的Filter。
Filter 运作方式
ASP.NET Core的每个Request都会先经过已注册的Middleware接着才会执行Filter,除了会依照上述的顺序外,同类型的Filter预设都会以先进后出的方式处里封包。
Response在某些Filter并不会做处理,会直接被pass。Request及Response的运作流程如下图:
- 黄色箭头是正常情况流程
- 灰色箭头是异常处理流程
建立Filter
ASP.NET Core的Filter基本上跟ASP.NET MVC的差不多。
上述的五种Filter范例分别如下:
Authorization Filter
AuthorizationFilter.cs
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc.Filters; namespace MyWebsite.Filters { public class AuthorizationFilter : IAuthorizationFilter { public void OnAuthorization(AuthorizationFilterContext context) { context.HttpContext.Response.WriteAsync($"{GetType().Name} in. \r\n"); } } }
非同步的方式:
// ... public class AuthorizationFilter : IAsyncAuthorizationFilter { public async Task OnAuthorizationAsync(AuthorizationFilterContext context) { await context.HttpContext.Response.WriteAsync($"{GetType().Name} in. \r\n"); } }
Resource Filter
ResourceFilter.cs
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc.Filters; namespace MyWebsite.Filters { public class ResourceFilter : IResourceFilter { public void OnResourceExecuting(ResourceExecutingContext context) { context.HttpContext.Response.WriteAsync($"{GetType().Name} in. \r\n"); } public void OnResourceExecuted(ResourceExecutedContext context) { context.HttpContext.Response.WriteAsync($"{GetType().Name} out. \r\n"); } } }
非同步的方式:
// ... public class ResourceFilter : IAsyncResourceFilter { public async Task OnResourceExecutionAsync(ResourceExecutingContext context, ResourceExecutionDelegate next) { await context.HttpContext.Response.WriteAsync($"{GetType().Name} in. \r\n"); await next(); await context.HttpContext.Response.WriteAsync($"{GetType().Name} out. \r\n"); } }
Action Filter
ActionFilter.cs
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc.Filters; namespace MyWebsite.Filters { public class ActionFilter : IActionFilter { public void OnActionExecuting(ActionExecutingContext context) { context.HttpContext.Response.WriteAsync($"{GetType().Name} in. \r\n"); } public void OnActionExecuted(ActionExecutedContext context) { context.HttpContext.Response.WriteAsync($"{GetType().Name} out. \r\n"); } } }
非同步的方式:
// ... public class ActionFilter : IAsyncActionFilter { public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) { await context.HttpContext.Response.WriteAsync($"{GetType().Name} in. \r\n"); await next(); await context.HttpContext.Response.WriteAsync($"{GetType().Name} out. \r\n"); } }
Result Filter
ResultFilter.cs
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc.Filters; namespace MyWebsite.Filters { public class ResultFilter : IResultFilter { public void OnResultExecuting(ResultExecutingContext context) { context.HttpContext.Response.WriteAsync($"{GetType().Name} in. \r\n"); } public void OnResultExecuted(ResultExecutedContext context) { context.HttpContext.Response.WriteAsync($"{GetType().Name} out. \r\n"); } } }
非同步的方式:
// ... public class ResultFilter : IAsyncResultFilter { public async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next) { await context.HttpContext.Response.WriteAsync($"{GetType().Name} in. \r\n"); await next(); await context.HttpContext.Response.WriteAsync($"{GetType().Name} out. \r\n"); } }
Exception Filter
ExceptionFilter.cs
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc.Filters; namespace MyWebsite.Filters { public class ExceptionFilter : IExceptionFilter { public void OnException(ExceptionContext context) { context.ExceptionHandled = true; // 表明异常已处理,客户端可得到正常返回 context.HttpContext.Response.WriteAsync($"{GetType().Name} in. \r\n"); } } }
非同步的方式:
// ... public class ExceptionFilter : IAsyncExceptionFilter { public Task OnExceptionAsync(ExceptionContext context) { context.ExceptionHandled = true;// 表明异常已处理,客户端可得到正常返回 context.HttpContext.Response.WriteAsync($"{GetType().Name} in. \r\n"); return Task.CompletedTask; } }
注册Filter
Filter有两种注册方式,一种是全局注册,另一种是用[Attribute]局部
注册的方式,只套用在特定的Controller或Action。
全局注册
在Startup.ConfigureServices
的MVC服务中注册Filter,这样就可以套用到所有的Request。如下:
// ... public class Startup { public void ConfigureServices(IServiceCollection services) { services.AddMvc(config => { config.Filters.Add(new ResultFilter()); config.Filters.Add(new ExceptionFilter()); config.Filters.Add(new ResourceFilter()); }); } }
局部注册
ASP.NET Core在局部注册Filter的方式跟ASP.NET MVC有一点不一样,要通过[TypeFilter(type)]
。
在Controller或Action上面加上[TypeFilter(type)]
就可以局部注册Filter。如下:
// ... namespace MyWebsite.Controllers { [TypeFilter(typeof(AuthorizationFilter))] public class HomeController : Controller { [TypeFilter(typeof(ActionFilter))] public void Index() { Response.WriteAsync("Hello World! \r\n"); } [TypeFilter(typeof(ActionFilter))] public void Error() { throw new System.Exception("Error"); } } }
[TypeFilter(type)]
用起来有点冗长,想要像过去ASP.NET MVC用[Attribute]
注册Filter的话,只要将Filter继承Attribute
即可。如下:
public class AuthorizationFilter : Attribute, IAuthorizationFilter { // ... } public class ActionFilter : Attribute, IActionFilter { // ... }
[Attribute]
注册就可以改成如下方式:
// ... namespace MyWebsite.Controllers { [AuthorizationFilter] public class HomeController : Controller { [ActionFilter] public void Index() { Response.WriteAsync("Hello World! \r\n"); } [ActionFilter] public void Error() { throw new System.Exception("Error"); } } }
执行结果
http://localhost:5000/Home/Index
输出结果如下:
AuthorizationFilter in. ResourceFilter in. ActionFilter in. Hello World! ActionFilter out. ResultFilter in. ResultFilter out. ResourceFilter out.
http://localhost:5000/Home/Error
输出结果如下:
AuthorizationFilter in. ResourceFilter in. ActionFilter in. ActionFilter out. ExceptionFilter in. ResourceFilter out.
执行顺序
预设注册同类型的Filter 是以先进后出的方式处里封包,注册层级也会影响执行顺序。
但也可以通过实现 IOrderedFilter 更改执行顺序。例如:
public class ActionFilter : Attribute, IActionFilter, IOrderedFilter { public string Name { get; set; } public int Order { get; set; } = 0; public void OnActionExecuting(ActionExecutingContext context) { context.HttpContext.Response.WriteAsync($"{GetType().Name}({Name}) in. \r\n"); } public void OnActionExecuted(ActionExecutedContext context) { context.HttpContext.Response.WriteAsync($"{GetType().Name}({Name}) out. \r\n"); } }
在注册Filter 时带上Order,数值越小优先权越高。
// ... public class Startup { public void ConfigureServices(IServiceCollection services) { services.AddMvc(config => { config.Filters.Add(new ActionFilter() { Name = "Global", Order = 3 }); }); } }
// ... namespace MyWebsite.Controllers { [ActionFilter(Name = "Controller", Order = 2)] public class HomeController : Controller { [ActionFilter(Name = "Action", Order = 1)] public void Index() { Response.WriteAsync("Hello World! \r\n"); } } }
变更执行顺序后的输出内容:
ActionFilter(Action) in. ActionFilter(Controller) in. ActionFilter(Global) in. Hello World! ActionFilter(Global) out. ActionFilter(Controller) out. ActionFilter(Action) out.
参考
老司机发车啦:
上一篇: 如果你得了狂犬病
下一篇: 懂幽默的夫妻,生活乐事多
推荐阅读
-
Orleans[NET Core 3.1] 学习笔记(四)( 2 )获取Grain的方式
-
.NET Core 学习笔记2——管理nuget包
-
ASP.NET Core笔记(2) - 依赖注入
-
ASP.NET Core 2 学习笔记(十三)Swagger
-
ASP.NET Core 2 学习笔记(六)
-
ASP.NET Core 2 学习笔记(十二)REST-Like API
-
ASP.NET Core 2 学习笔记(十一)Cookies & Session
-
ABP框架(asp.net core 2.X+Vue)模板项目学习之路(一)
-
ASP.NET Core 2 学习笔记(九)模型绑定
-
张高兴的 Windows 10 IoT 开发笔记:部署 ASP.NET Core 2 应用