前情提要
筆者負責的專案,是那種到處要跟第三方串接那種,第三方不管是內部或多個外部,串接方式不外乎就是WebService
或是Restful API
,或者提供dll
檔案,多種形式見怪不怪,串接這時候釐清問題是最重要的,因此必須要確保我方系統上保有Request
及Response
以釐清問題,也是自保的一種概念,因為你無法保證串接的Method
跟金額無關,這時候唯有留下系統軌跡才能保證你的清白(被害妄想症上身中),筆者相信留下紀錄這件事,不管事不是跟別的系統串接,仍是很重要的課題。
然而對於Restful API
這種串接方式,最方便留下紀錄了,只要共用一個HttpClientRepository
,將發出HttpRequest
集中在某一個Method
中,方便事後增加其往來紀錄的相關程式碼,當然我方系統是被呼叫方的話,也是可以透過DotnetCore
內建的Middleware
能搞定。至於呼叫WebService
或者dll
檔案中的Method
則比較傷腦筋一點,動用到今天的主角,AOP Logging
,能夠輕鬆地不留痕跡地做到留下紀錄。
AOP Logging選項
AOP: Aspect Oriented Programming
,筆者這邊就不贅述了,網路上文章太多了,基本上dotnetcore
上的Middleware
應該就算是AOP
的實作,且還有Pipeline
的概念,一個接一個執行,筆者當初的想法也是如此,有沒有辦法找到類似像Middleware
套用在一般的Service Method
上,筆者現在都跳過Google
,直接丟問題給ChatGPT
了
1 | List the nuget package that can be logged method input and output like middleware, AOP pattern using dotnet core DI framework |
還真的找到滿像樣的回答
以ChatGPT
回答來說,筆者大概猜得出來,除了第一個之外,其他都是第三方DI套件的附加功能,筆者專案皆是透過dotnet core
內建的DI
功能在注入使用所有相關Service
,固然選第一個套件來survey
了,這時候再用google
搜尋該套件,找到該套件的github
一探究竟,找到document
,有了document
就好辦事了。
安裝對應套件
筆者就使用ChatGPT推薦的第一個套件了,因為等等會分兩個部分註冊
- Interceptor
- DynamicProxyProvider
以筆者的專案配置來說,會是Service
專案及Web
專案皆要安裝對應的套件
1 | dotnet add package AspectCore.Extensions.DependencyInjection |
製作LoggingInterceptor
首先要先製作一個LoggingInterceptor
1 | public class ServiceMethodLoggingInterceptor : AbstractInterceptorAttribute |
依上面的
Code
說明一下對應關係,因為跟本文無關就只列出概念性的解釋,想要參考的各位,請務必換成自己專案對應的寫法
ApiLog
,對應筆者專案使用的Log
資料表(因為都是屬於第三方串接,與Restful API
紀錄共用)GenericRepository
,筆者專案使用的CRUD
的Repository(單檔都透過它完成)Adapt
方法,則是Mapster套件的功能,與AutoMapper
功能相似,簡單用,效能更好- 筆者這邊將物件變更都集中在該物件類別中,因此設計
UpdateResponseInfo
,透過此方法變更其值 ApiRequestPipelineModel
,筆者這邊是偷用AddScoped
的好處,該物件建構式中初始化一個GUID
放著,一個Request
中經過的任何Service
,只要注入該物件,都會拿到相同的GUID
,以拿來關聯各種資料為同一個Request
的追查依據
註冊Interceptor
接著要透過註冊的方式註冊其上面寫的ServiceMethodLoggingInterceptor
1 | using AspectCore.Configuration; |
註冊方式有很多種,參考中的使用指南都有示範,筆者用慣建構式注入的方式引用其對應的實作,因此
- 透過
AddSingleton
的方式註冊其Interceptor
- 透過
AddServiced
的方式新增其Interceptor
至DynamicProxyProvider
中 - 筆者這邊有指定某
XXXService
,因筆者把呼叫Dll
對應的方法都集中在該Service Class
中,若全域套用則不需增加此設定 - 筆者這邊習慣在某一個
Project
中的Service
註冊集中在該Project
的某一個Extension
中,相關註冊對應程式碼可直接宣告在Startup
中的ConfigureService
即可
註冊DynamicProxyProvider
最後需要在Program
那邊要作手腳,才算大功告成
1 | using AspectCore.Extensions.DependencyInjection; |
結論
筆者喜歡AOP
設計的原因就是在此文章中根本沒看到商業邏輯程式,意思就是完全不用動到主程式,就能做到紀錄Input
, Output
的功能,超棒的,且因為該套件設計是可以指定套用該Interceptor
的服務名稱,更上一層樓了,只要改動註冊的地方,其他商業邏輯主程式也輕易地享有Logging的功能,這就是AOP設計的魅力所在,今天的分享就到這了,下篇見。
參考