ASP.NET Core 5 EP 14:Filter-封包篩選條件管線化
什麼是Filter
Filter是於Action前/後所被定義用作處理封包的功能,其定義有5種Filter,包括Authorization Filter、Resource Filter、Action Filter、Exception Filter 及 Result Filter,其功能分別如下:
- Authorization Filter
用於檢查Request授權檢查的Filter,也是所有Filter第一個被執行的。 - Resource Filter
執行順序在 Authorization 之後,Model Binding 之前執行,用作對 Model 加工處理。 - Action Filter
封包進出都會經過Action Filter,跟 Resource Filter 很類似,但不會經過 Model Binding。 - Exception Filter
異常處理的Filter,可以制定統一的HTTP回應機制。 - Result Filter
Request的最後一關、Response的第一關。
各種Filter的執行順序如下圖:
實作Filter
接著,按照5種Filter的順序來實作,我們聚焦在Filter的同步/非同步與宣告部分,而不實做內容,例如,Authorization Filter,會提出宣告同步與非同步的方式,但不實做JWT或Oauth。
Authorization Filter
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Filters;
namespace CookbookApi.Filters
{
public class AuthFilter : IAuthorizationFilter, IAsyncAuthorizationFilter
{
// 同步方法
public void OnAuthorization(AuthorizationFilterContext context)
{
// ...
}
// 非同步方法
public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
{
// ... await
}
}
}
Resource Filter
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Filters;
namespace CookbookApi.Filters
{
public class ResourceFilter : IResourceFilter, IAsyncResourceFilter
{
// 同步方法 - 執行完成後
public void OnResourceExecuted(ResourceExecutedContext context)
{
// ...
}
// 同步方法 - 執行前
public void OnResourceExecuting(ResourceExecutingContext context)
{
// ...
}
// 非同步方法 - 執行中
public async Task OnResourceExecutionAsync(ResourceExecutingContext context, ResourceExecutionDelegate next)
{
// ... await next();
}
}
}
Action Filter
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Filters;
namespace CookbookApi.Filters
{
public class ActionFilter : IActionFilter, IAsyncActionFilter
{
// 同步方法 - 執行完成後
public void OnActionExecuted(ActionExecutedContext context)
{
// ...
}
// 同步方法 - 執行前
public void OnActionExecuting(ActionExecutingContext context)
{
// ...
}
// 非同步方法 - 執行中
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
// ... await next();
}
}
}
Exception Filter – 同步
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Filters;
namespace CookbookApi.Filters
{
public class ExceptionFilter : IExceptionFilter, IAsyncExceptionFilter
{
// 同步方法
public void OnException(ExceptionContext context)
{
// ...
}
// 非同步方法
public async Task OnExceptionAsync(ExceptionContext context)
{
// ... await
}
}
}
Result Filter – 同步
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Filters;
namespace CookbookApi.Filters
{
public class ResultFilter : IResultFilter, IAsyncResultFilter
{
// 同步方法 - 執行完成後
public void OnResultExecuted(ResultExecutedContext context)
{
// ...
}
// 同步方法 - 執行前
public void OnResultExecuting(ResultExecutingContext context)
{
// ...
}
// 非同步方法 - 執行中
public async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
{
// ... await next();
}
}
}
註冊Filter
全域註冊:在Startup.cs中的ConfigureServices中加入註冊的方法。
// ...
public void ConfigureServices(IServiceCollection services)
{
// ...
// 註冊的順序不代表執行順序,還是依照系統的規定運作
services.AddMvc(config =>{
config.Filters.Add(new Filters.AuthFilter());
config.Filters.Add(new Filters.ResourceFilter());
config.Filters.Add(new Filters.ActionFilter());
config.Filters.Add(new Filters.ExceptionFilter());
config.Filters.Add(new Filters.ResultFilter());
});
}
區域註冊:若要註冊Filters.ActionFilter,可以在Controller中的任一個函數加入標籤[TypeFilter(typeof(Filters.ActionFilter))],如下所示:
// 區域註冊Filter
[TypeFilter(typeof(Filters.ActionFilter))]
// 區域註冊Middleware
[MiddlewareFilter(typeof(Middleware.ReqHeaderChecker))]
// 設定這個API使用HEAD方法
[HttpHead]
// 設定這個API使用GET方法
[HttpGet]
public IActionResult Get()
{
// 宣告一個食譜的Model,並呼叫Libs.Recipe.Get函數取得資料
Models.Resipe objResipe = Libs.Recipe.Get();
// 回傳HTTP 200,內容為糖醋排骨的食譜資料
return Ok(objResipe);
}
若標籤[TypeFilter(typeof(Filters.ActionFilter))]放在最外層的class,那表示這整個Controller都會套用這個Filter。
~ END ~