前情提要
筆者負責的專案,是那種到處要跟第三方串接那種,第三方不管是內部或多個外部,串接方式不外乎就是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設計的魅力所在,今天的分享就到這了,下篇見。
參考