前情提要
筆者最近在公司負責開發一個全新的API
對外系統,因沒有舊系統包袱,可以設計統一Response
,統一的ExceptionHandlerMiddleware
,只多不嫌少的各種CustomizeException
等等,然而接受客戶端的Request
時,勢必要進行Validation
作業,可以重捨FluentValidation
的懷抱了,此篇就以筆者遇到的情境及解法介紹為主,讓我們看下去吧。
先列一下筆者這邊使用的套件的版本號
Fluent Validation
11.7.1
Fluent.Validation.AspNetCore
11.3.0
再來敘述一下筆者這邊的環境遇到的問題,因EncryptKey
放在資料庫的因素,需要Validator
中連線資料庫並取得EncryptKey
,這樣才能提早驗證客戶端傳來的加密字串是否可以成功解密,就不用等到商業邏輯處理時才爆錯,DB Access
相關程式碼會使用到Async
方法,參考https://docs.fluentvalidation.net/en/latest/async.html此篇中的說明,不適用ASP.Net Core
的Validaion Pipeline
,等於沒有使用到AutoValidation的好處,自己需要爾外透過IVlidator<T>.Validate
這種手動驗證的方式進行驗證,也因此無法透過設定ConfigureApiBehaviorOptions
來指定InvalidModelStateResponseFactory
的統一Response
,稍嫌可惜,筆者說的都在這篇文章上https://medium.com/codex/custom-error-responses-with-asp-net-core-6-web-api-and-fluentvalidation-888a3b16c80f。
驗證思路
筆者想像中,在每一個Action
開頭中多了一個Validate
的作業,只是型別不一樣,但行為是一致的
1 | public class OrderController: ControllerBase |
寫到這邊筆者想起剛開始撰寫MVC5
的時候,老是想用上ActionFilter
,盡量讓統一行為在ActionFilter
中進行,達到DRY
的精神。但不外乎常用到的情境就是ModelState
的驗證,不過時回應統一的Response
,這次情境只是多了一個型別的宣告,那就來用各Generic Action Filter
吧,接著就誕生ValidationFilterAttribute
實作IAsyncActionFilter
因為非同步的行為,筆者這邊採用IAsyncActionFilter
1 | public class ValidationFilterAttribute<T> : IAsyncActionFilter |
註冊IAsyncActionFilter
註冊方式是滿簡單的,筆者這邊就透過dotnet core
預設的DI,註冊為Scope
類型服務
1 | services.AddScoped(typeof(ValidationFilterAttribute<>)); |
套用IAsyncActionFilter
撰寫完畢,註冊完成後,將套用在想套用的Action
上吧
1 | public class OrderController : ControllerBase |
設定CascadeMode
依照Validate
的角度來說,有前後相依性的,以筆者這邊的例子來說,加密字串為空的,根本不需要驗證解密是否可以成功,且解密驗證關係到連線資料庫,若能夠於加密字串為空這個Validation Rule
驗證不過時,就不用往下驗證,對於執行效能來說是好的,FluentValidation
也有提供其方便設定的方式,依照版本參考對應的設定,筆者這邊的版本11來說,分為
- Global Level
- Class Level
- Rule Level
1 | public class OrderRequestValidator : AbstractValidator<OrderRequestDto> |
結論
因目前開發的是一個全新的API
站台對外系統,比較沒有舊系統的包袱,可以照比較正統的方式設計其系統,各司其職的概念,尚未包含商業邏輯簡單驗證還是交給Fluent Validation
,擋在前面,到Service
層就專心處理商業邏輯就好,職責明確之外,也少了很多code
塞在同一個地方窘境,偵錯起來也不會亂,一舉數得,還不行動嗎?
參考
- https://docs.fluentvalidation.net/en/latest/index.html
- https://learn.microsoft.com/zh-tw/aspnet/core/mvc/controllers/filters?view=aspnetcore-7.0#dependency-injection
- [DotnetCore]後端驗證神器:Fluent Validation