一、前言
在分享ASP.NET Core Filter 使用之前,先來談?wù)凙OP,什么是AOP 呢?
AOP全稱Aspect Oriented Programming
意為面向切面編程,也叫做面向方法編程,是通過預(yù)編譯方式和運行期動態(tài)代理的方式實現(xiàn)不修改源代碼的情況下給程序動態(tài)統(tǒng)一添加功能的技術(shù)。
AOP技術(shù)利用一種稱為“橫切”的技術(shù),剖解開封裝對象的內(nèi)部,將影響多個類的公共行為封裝到一個可重用的模塊中,并將其命名為Aspect
切面。所謂的切面,簡單來說就是與業(yè)務(wù)無關(guān),卻為業(yè)務(wù)模塊所共同調(diào)用的邏輯,將其封裝起來便于減少系統(tǒng)的重復(fù)代碼,降低模塊的耦合度,有利用未來的可操作性和可維護性。
利用AOP可以對業(yè)務(wù)邏輯各個部分進行隔離,從而使業(yè)務(wù)邏輯各部分之間的耦合度降低,提高程序的可重用性,同時提高開發(fā)效率。
AOP的使用場景主要包括日志記錄、性能統(tǒng)計、安全控制、事務(wù)處理、異常處理等。
二、Filter-過濾器
Filter是延續(xù)ASP.NET MVC的產(chǎn)物,同樣保留了五種的Filter,分別是Authorization Filter、Resource
Filter、Action Filter、Exception Filter及Result Filter。
通過不同的Filter可以有效處理封包進出的加工,本篇將介紹ASP.NET Core的五種Filter運作方式。
2.1 Filter 介紹
ASP.NET Core 有以下五種Filter 可以使用:
* Authorization Filter:
Authorization是五種Filter中優(yōu)先級最高的,通常用于驗證Request合不合法,不合法后面就直接跳過。
* Resource Filter:Resource是第二優(yōu)先,會在Authorization之后,Model
Binding之前執(zhí)行。通常會是需要對Model加工處理才用。
* Exception Filter:異常處理的Filter。
* Action Filter:最常使用的Filter,封包進出都會經(jīng)過它,使用上沒什么需要特別注意的。跟Resource
Filter很類似,但并不會經(jīng)過Model Binding。
* Result Filter:當(dāng)Action完成后,最終會經(jīng)過的Filter。
三、五大Filter 的應(yīng)用
這一篇章主要來講解Asp.Net Core 的五大過濾器的實現(xiàn)及用途.
3.1 Authonization Filter
權(quán)限控制過濾器
通過 Authonization Filter 可以實現(xiàn)復(fù)雜的權(quán)限角色認(rèn)證、登陸授權(quán)等操作
實現(xiàn)事例代碼如下:
public class AuthonizationFilter :Attribute,IAuthorizationFilter { public
void OnAuthorization(AuthorizationFilterContext context) { //這里可以做復(fù)雜的權(quán)限控制操作 if
(context.HttpContext.User.Identity.Name != "1") //簡單的做一個示范 { //未通過驗證則跳轉(zhuǎn)到無權(quán)限提示頁
RedirectToActionResult content = new RedirectToActionResult("NoAuth",
"Exception", null); context.Result = content; } } }
3.2 Resource Filter
資源過濾器
可以通過Resource Filter 進行資源緩存、防盜鏈等操作。
使用Resource Filter 要求實現(xiàn)IResourceFilter 抽象接口
public class ResourceFilter : Attribute,IResourceFilter { public void
OnResourceExecuted(ResourceExecutedContext context) { // 執(zhí)行完后的操作 } public void
OnResourceExecuting(ResourceExecutingContext context) { // 執(zhí)行中的過濾器管道 } }
3.3 Exception Filter
通過Execption Filter 過濾器可以進行全局的異常日志收集 等操作。
使用Execption Filter 要求實現(xiàn)IExceptionFilter 抽象接口
IExceptionFilter接口會要求實現(xiàn)OnException方法,當(dāng)系統(tǒng)發(fā)生未捕獲異常時就會觸發(fā)這個方法。OnException方法有一個
ExceptionContext
異常上下文,其中包含了具體的異常信息,HttpContext及mvc路由信息。系統(tǒng)一旦出現(xiàn)未捕獲異常后,比較常見的做法就是使用日志工具,將異常的詳細(xì)信息記錄下來,方便修正調(diào)試。下面是日志記錄的實現(xiàn)。
public class ExecptionFilter : Attribute, IExceptionFilter { private
ILogger<ExecptionFilter> _logger; //構(gòu)造注入日志組件 public
ExecptionFilter(ILogger<ExecptionFilter> logger) { _logger = logger; } public
void OnException(ExceptionContext context) { //日志收集
_logger.LogError(context.Exception, context?.Exception?.Message??"異常"); } }
3.4 Action Filter
作用:可以通過ActionFilter 攔截 每個執(zhí)行的方法進行一系列的操作,比如:執(zhí)行操作日志、參數(shù)驗證,權(quán)限控制 等一系列操作。
使用Action Filter 需要實現(xiàn)IActionFilter 抽象接口,IActionFilter 接口要求實現(xiàn)OnActionExecuted 和
OnActionExecuting 方法
public class ActionFilter : Attribute, IActionFilter { public void
OnActionExecuted(ActionExecutedContext context) { //執(zhí)行完成.... } public void
OnActionExecuting(ActionExecutingContext context) { //執(zhí)行中... } }
3.5 Result Filter
結(jié)果過濾器,可以對結(jié)果進行格式化、大小寫轉(zhuǎn)換等一系列操作。
使用Result Filter 需要實現(xiàn)IResultFilter 抽象接口,接口要求實現(xiàn)
OnResultExecuting 方法 和OnResultExecuted 方法
* OnResultExecuting :Called before the action result executes. 在操作結(jié)果執(zhí)行之前調(diào)用
* OnResultExecuted :Called after the action result executes. 在操作結(jié)果執(zhí)行之后調(diào)用
具體代碼實現(xiàn)代碼如下:
public class ResultFilter : Attribute, IResultFilter { public void
OnResultExecuted(ResultExecutedContext context) { // 在結(jié)果執(zhí)行之后調(diào)用的操作... } public
void OnResultExecuting(ResultExecutingContext context) { // 在結(jié)果執(zhí)行之前調(diào)用的一系列操作 } }
四、Asp.Net Core 過濾器的注冊方式
這一篇章主要來分析探討Asp.Net Core 中過濾器的三種注冊方式Action、Controller、全局 。
4.1 Action 注冊方式
Action 注冊方式是局部注冊方式,針對控制器中的某個方法上標(biāo)注特性的方式進行注冊,代碼如下:
[AuthonizationFilter()] public IActionResult Index() { return View(); }
4.2 Controller 注冊方式
了解過Action 特性注冊方式的同學(xué),一定發(fā)現(xiàn)了它的不好之處就是我一個控制器里面需要使用同一套Filter 的時候,需要一個一個Action
標(biāo)注特性注冊,是不是很繁瑣呢?有沒有其他方式進行代替這些繁瑣的操作呢?微軟給我們提供了簡便的控制器標(biāo)注注冊方式,代碼如下:
[AuthonizationFilter()] public class FirstController : Controller { private
ILogger<FirstController> _logger; public
FirstController(ILogger<FirstController> logger) { _logger = logger; } public
IActionResult Index() { return View(); } }
4.3 全局注冊方式
現(xiàn)在有些同學(xué)考慮了一些全局的情況,比如我要全局處理系統(tǒng)中的異常,或者收集操作日志等,需要全局注冊一個ExceptionFilter
來實現(xiàn),就不需要每一個Controller 中進行代碼注冊,方便快捷。代碼如下:
public void ConfigureServices(IServiceCollection services) { //全局注冊異常過濾器
services.AddControllersWithViews(option=> {
option.Filters.Add<ExecptionFilter>(); });
services.AddSingleton<ISingletonService, SingletonService>(); }
4.4 TypeFilter 和 ServiceFilter 注冊方式
上面的五大過濾器中事例代碼中其中有一個過濾器的代碼比較特,再來回顧ExceptionFilter過濾器的實現(xiàn)代碼:
public class ExecptionFilter : Attribute, IExceptionFilter { private
ILogger<ExecptionFilter> _logger; //構(gòu)造注入日志組件 public
ExecptionFilter(ILogger<ExecptionFilter> logger) { _logger = logger; } public
void OnException(ExceptionContext context) { //日志收集
_logger.LogError(context.Exception, context?.Exception?.Message??"異常"); } }
從上面的代碼中可以發(fā)現(xiàn) ExceptionFilter
過濾器實現(xiàn)中存在日志服務(wù)的構(gòu)造函數(shù)的注入,也就是說該過濾器依賴于其他的日志服務(wù),但是日志服務(wù)都是通過DI 注入進來的;再來回顧下上面Action
注冊方式或者Controller 注冊方式 也即Attribute
特性標(biāo)注注冊方式,本身基礎(chǔ)的特性是不支持構(gòu)造函數(shù)的,是在運行時注冊進來的,那要解決這種本身需要對服務(wù)依賴的過濾器需要使用TypeFilter 或者
ServiceFilter 方式進行過濾器的標(biāo)注注冊。
TypeFilter 和ServiceFilter 的區(qū)別。
* ServiceFilter和TypeFilter都實現(xiàn)了IFilterFactory
* ServiceFilter需要對自定義的Filter進行注冊,TypeFilter不需要
* ServiceFilter的Filter生命周期源自于您如何注冊,而TypeFilter每次都會創(chuàng)建一個新的實例
TypeFilter 使用方式
代碼如下:
[TypeFilter(typeof(ExecptionFilter))] public IActionFilter Index2() { return
View(); }
通過上面的代碼可以發(fā)現(xiàn)AuthonizationFilter
是默認(rèn)的構(gòu)造器,但是如果過濾器中構(gòu)造函數(shù)中存在參數(shù),需要注入服務(wù)那該怎么辦呢?,比如上面的ExceptionFilter
代碼,就不能使用這種方式進行注冊,需要使用服務(wù)特性的方式,我們可以選擇使用 代碼如下:
[TypeFilter(typeof(ExecptionFilter))] public IActionFilter Index2() { return
View(); }
ServiceFilter 使用方式
控制器中的代碼如下:
[ServiceFilter(typeof(ExecptionFilter))] public IActionFilter Index2() {
return View(); }
注冊服務(wù)的代碼如下:
// This method gets called by the runtime. Use this method to add services to
the container. public void ConfigureServices(IServiceCollection services) {
Console.WriteLine("ConfigureServices"); services.AddControllersWithViews();
//services.AddControllersWithViews(option=> { //
option.Filters.Add<ExecptionFilter>(); //}); //注冊過濾器服務(wù),使用ServiceFilter 方式必須要注冊
否則會報沒有注冊該服務(wù)的相關(guān)異常 services.AddSingleton<ExecptionFilter>(); }
如果您覺的不錯,請微信掃碼關(guān)注 【dotNET 博士】公眾號,后續(xù)給您帶來更精彩的分享
熱門工具 換一換