“作為面向服務架構(SOA)的一個變體,微服務是一種將應用程式分解成鬆散耦合服務的新型架構風格. 透過細粒度的服務和輕量級的協議,微服務提供了更多的模組化,使應用程式更容易理解,開發,測試,並且更容易抵抗架構侵蝕. 它使小型團隊能夠開發,部署和擴充套件各自的服務,實現開發的並行化.它還允許透過連續重構形成單個服務的架構. 基於微服務架構可以實現持續交付和部署.”
— 維基百科
介紹
ABP框架的主要標的之一就是提供便捷的基礎設施來建立微服務解決方案.
此示例演示了一個簡單而完整的微服務解決方案;
- 擁有多個可獨立可單獨部署的微服務.
- 多個Web應用程式, 每一個都使用不同的API閘道器.
- 使用Ocelot庫開發了多個閘道器 / BFFs (用於前端的後端).
- 包含使用IdentityServer框架開發的 身份認證服務. 它也是一個帶有UI的SSO(單點登陸)應用程式.
- 有多個資料庫. 一些微服務有自己的資料庫,也有一些服務/應用程式共享同一個資料庫(以演示不同的用例).
- 有不同型別的資料庫: SQL Server (與 Entity Framework Core ORM) 和 MongoDB.
- 有一個控制檯應用程式使用身份驗證展示使用服務最簡單的方法.
- 使用Redis做分散式快取.
- 使用RabbitMQ做服務間的訊息傳遞.
- 使用 Docker & Kubernates 來部署&執行所有的服務和應用程式.
- 使用 Elasticsearch & Kibana 來儲存和視覺化日誌 (使用Serilog寫日誌).
下圖顯示了該系統:
原始碼
你可以從GitHub倉庫獲取原始碼.
狀態
此示例仍處於開發階段,尚未完成.
執行解決方案
您可以從 原始碼 或者預先配置好的 docker-compose 檔案執行.
使用Docker容器
預先要求
由於所有依賴項都已預先配置, 因此作為Docker容器執行更容易. 你只需要安裝最新的docker.
執行容器
-
克隆或下載 ABP倉庫.
-
在儲存庫的
samples/MicroserviceDemo
檔案夾中開啟命令列. -
從Docker Hub中拉取image:
docker-compose -f docker-compose.yml -f docker-compose.migrations.yml pull
-
如果要在本地構建映像, 可以跳過上述步驟, 使用build命令:
docker-compose -f docker-compose.yml -f docker-compose.migrations.yml build
根據你的電腦配置, 構建image可能需要很長時間.
-
還原 SQL Server 資料庫:
docker-compose -f docker-compose.yml -f docker-compose.migrations.yml run restore-database
-
啟動容器:
docker-compose up -d
-
將此行新增到
hosts
檔案的末尾:127.0.0.1 auth-server
hosts檔案位於Windows上的
C:\Windows\System32\Drivers\etc\hosts
檔案夾, Linux/MacOS的/etc/hosts
中.
執行應用程式
你可能想要瞭解容器中執行一些應用程式:
- 後端管理應用程式 (BackendAdminApp.Host):
http://localhost:51512
(用於管理系統中的使用者和產品) - 公共網站 (PublicWebsite.Host):
http://localhost:51513
(用於列出產品並執行/管理部落格模組) - 認證伺服器 (AuthServer.Host):
http://auth-server:51511/
(用作使用IdentityServer4構建的單點登入和身份驗證伺服器) - Kibana UI:
http://localhost:51510
(用於顯示/跟蹤所有服務/應用程式/閘道器寫入的日誌)
從原始碼執行
預先要求
為了能夠從原始碼執行解決方案, 應在你的計算機上安裝並執行以下工具:
- SQL Server 2015+ (可以是 express edition)
- Redis 5.0+
- RabbitMQ 3.7.11+
- MongoDB 4.0+
- ElasticSearch 6.6+
- Kibana 6.6+ (可選,建議顯示日誌)
開啟並構建Visual Studio解決方案
- 在Visual Studio 2017 (15.9.0+)中開啟
samples\MicroserviceDemo\MicroserviceDemo.sln
. - 在
samples\MicroserviceDemo
檔案夾中的命令列執行dotnet restore
命令. - 在Visual Studio中構建解決方案.
還原資料庫
在samples\MicroserviceDemo\databases
檔案夾中開啟MsDemo_Identity.zip
和MsDemo_ProductManagement.zip
並恢復到SQL Server.
請註意:這些資料庫在解決方案中具有EF Core遷移,但它們沒有種子資料,尤其是IdentityServer4所需的配置. 因此,恢復資料庫要容易得多.
執行專案
按以下順序執行專案(右鍵單擊每個專案設定為啟動專案,按Ctrl+F5執行,無需除錯):
- AuthServer.Host
- IdentityService.Host
- BloggingService.Host
- ProductService.Host
- InternalGateway.Host
- BackendAdminAppGateway.Host
- PublicWebSiteGateway.Host
- BackendAdminApp.Host
- PublicWebSite.Host
解決方案簡介
Visual Studio解決方案由多個專案組成,每個專案在系統中具有不同的角色:
應用程式(Applications)
這些是具有使用者介面以與使用者互動並使用系統的實際應用程式.
- AuthServer.Host: 託管IdentityServer4以向其他服務和應用程式提供身份驗證服務. 它是一個單點登入伺服器,包含登入頁面.
- BackendAdminApp.Host: 這是一個後端管理應用程式,用於託管身份和產品管理模組的UI.
- PubicWebSite.Host: 作為包含簡單產品串列頁面和部落格模組UI的公共網站.
- ConsoleClientDemo: 一個簡單的控制檯應用程式,用於演示C#應用程式中使用服務.
閘道器/BFF(前端後端)
閘道器用於為應用程式提供單一入口點.它還可以用於速率限制,負載平衡等. 使用Ocelot類庫.
- BackendAdminAppGateway.Host: 由BackendAdminApp.Host應用程式用作後端.
- PublicWebSiteGateway.Host: 由PublicWebSite.Host應用程式用作後端.
- InternalGateway.Host: 用於服務間通訊(微服務之間的通訊).
微服務
微服務沒有UI,但暴露了一些REST API.
- IdentityService.Host: 託管用於管理使用者和角色的ABP Identity模組. 它沒有其他服務,僅託管Identity模組的API.
- BloggingService.Host: 託管ABP部落格模組,該模組用於管理部落格和帖子(典型的部落格應用程式). 它沒有其他服務,僅託管Blogging模組的API.
- ProductService.Host: 託管用於管理產品的產品模組(位於解決方案內). 它還包含用於建立/更新產品管理資料庫架構的EF Core遷移.
模組
- 產品: 使用模組開發最佳實踐開發的分層模組. 它可以嵌入到單個應用程式中,也可以透過單獨部署API和UI作為微服務託管(如本演示解決方案中所述).
資料庫
此解決方案使用多個資料庫:
- MsDemo_Identity: 一個SQL資料庫. 預設使用** SQL Server **,但可以是EF Core支援的任何DBMS. 由AuthServer和IdentityService共享. 審計日誌,許可權和設定也儲存在此資料庫中(雖然它們可以輕鬆擁有自己的資料庫,共享相同的資料庫以保持簡單).
- MsDemo_ProductManagement: 一個SQL資料庫. 同樣預設使用 SQL Server,但可以是EF Core支援的任何DBMS. 由ProductService用作專用資料庫.
- MsDemo_Blogging: MongoDB資料庫. 由BloggingService使用.
- Elasticsearch: 用於在Serilog上寫日誌.
應用
認證伺服器 (AuthServer.Host)
所有其他服務和應用程式都使用此專案進行身份驗證和單點登入. 主要使用IdentityServer4來提供這些服務. 它使用了一些預構建ABP模組 如 Identity, Audit Logging 和 Permission Management.
資料庫和EF Core配置
此應用程式使用SQL資料庫(將其命名為MsDemo_Identity)並透過Entity Framework Core遷移維護其架構.
它有一個名為AuthServerDbContext的DbContext,定義如下:
在OnModelCreating方法中, 你會看到 ConfigureX() 方法呼叫. 具有資料庫樣式的模組通常宣告這樣的擴充套件方法,以便為其自己的物體配置EF Core對映. 這是一種靈活的方法, 可以在其中安排資料庫和模組; 可以為每個模組使用不同的資料庫,或者將它們中的一些組合在一個共享資料庫中. 在AuthServer專案中,我們決定在單個物理資料庫中將單個EF Core DbContext中的多個模組樣式組合在一起. 這些模組是Identity,IdentityServer,AuditLogging,PermissionManagement和SettingManagement模組.
請註意,此DbContext僅用於資料庫遷移. 所有模組都有自己的DbContext
類,模組在執行時使用這些類.
使用者介面
AuthServer有一個簡單的主頁,如果當前使用者已登入,則顯示當前使用者資訊:
它還提供登入和註冊頁面:
這些頁面不包含在專案本身中. 相反,AuthServer專案使用帶有IdentityServer擴充套件的預構建ABP帳戶模組. 這意味著它還可以充當具有必要UI和邏輯的OpenId Connect伺服器.
依賴
- RabbitMQ 用於向其他服務傳送訊息.
- Redis 用於分散式/共享快取.
- Elasticsearch 用於儲存日誌.
後端管理應用程式 (BackendAdminApp.Host)
這是一個Web應用程式,用於管理系統中的使用者,角色,許可權和產品.
認證
BackendAdminApp重定向到AuthServer進行身份驗證. 使用者輸入正確的使用者名稱和密碼後,頁面將再次重定向到後端應用程式. 身份驗證配置在BackendAdminAppHostModule
類中設定:
- 它將”Cookies”身份驗證新增為主要身份驗證型別.
- “oidc”身份驗證配置為使用AuthServer應用程式作為身份驗證伺服器.
- 它需要額外的身份範圍(scopes) role, email and phone.
- It requires the API resource scopes BackendAdminAppGateway, IdentityService and ProductServicebecause it will use these services as APIs.
- 它需要API資源範圍 BackendAdminAppGateway, IdentityService 和 ProductService,因為它將這些服務用作API.
IdentityServer客戶端設定儲存在appsettings.json
檔案中:
使用者介面
BackendAdminApp.Host專案本身沒有單個UI元素/頁面. 它僅用於提供身份和產品管理模組的UI頁面.
BackendAdminAppHostModule
將依賴關係新增到AbpIdentityWebModule
(Volo.Abp.Identity.Web 包)和ProductManagementWebModule
(ProductManagement.Web專案)為此目的.
使用者管理頁面的螢幕截圖:
來自許可權的許可權管理樣式的螢幕截圖:
使用微服務
後端管理應用程式透過後端管理閘道器對所有操作使用Identity和Product微服務(BackendAdminAppGateway.Host).
遠端端點
appsettings.json
檔案包含RemoteServices
部分,用於宣告遠端服務端點. 每個微服務通常都有不同的端點. 但是,此解決方案使用API閘道器樣式為應用程式提供單個端點:
http://localhost:65115/
是 BackendAdminAppGateway.Host 專案的URL. 它知道身份和產品服務的位置.
HTTP Clients
ABP應用程式模組通常提供C#客戶端庫以輕鬆地使用服務(API)(它們通常使用ABP框架的Dynamic C# API客戶端). 這意味著如果你需要使用Identity Service API, 你可以取用其客戶端軟體包,並透過提供的介面輕鬆使用API.
為此BackendAdminAppHostModule
類宣告了AbpIdentityHttpApiClientModule
和ProductManagementHttpApiClientModule
的依賴關係.
一旦取用這些客戶端軟體包,就可以直接註入應用程式服務介面(例如IIdentityUserAppService
)並使用其方法,如本地方法呼叫. 它實際上透過HTTP呼叫到相關服務端點的遠端服務呼叫.
傳遞訪問令牌(Access Token)
由於微服務需要身份驗證和授權,因此每個遠端服務呼叫都應包含Authentication頭. 該頭是從當前使用者的當前HttpContext
中的access_token
獲得的. 當你使用Volo.Abp.Http.Client.IdentityModel
包時,會自動執行此操作. BackendAdminAppHostModule
宣告對此包和相關的AbpHttpClientIdentityModelModule
類的依賴. 它整合到上面解釋的HTTP客戶端.
依賴
- Redis 用於分散式/共享快取.
- Elasticsearch 用於儲存日誌.
公共網站 (PublicWebSite.Host)
這是一個公共網站專案,具有Web部落格和產品串列頁面.
認證
公共網站可以在不登入的情況下顯示部落格文章和產品串列. 如果你登入,你還可以管理部落格. 它重定向到AuthServer進行身份驗證. 使用者輸入正確的使用者名稱和密碼後,頁面將再次重定向到公共網站應用程式. 身份驗證配置在PublicWebSiteHostModule
類中設定:
- 它將”Cookies”身份驗證新增為主要身份驗證型別.
- “oidc”身份驗證配置為使用AuthServer應用程式作為身份驗證伺服器.
- 它需要額外的身份範圍 role, email and phone.
- 它需要API資源範圍 PublicWebSiteGateway,BloggingService和ProductService,因為它將這些服務用作API.
IdentityServer客戶端設定儲存在appsettings.json
檔案中:
使用者介面
PublicWebSite.Host專案有一個列出產品的頁面 (Pages/Products.cshtml
). 它還使用部落格模組中的UI. 為此PublicWebSiteHostModule
加入了BloggingWebModule
(Volo.Blogging.Web 包)的依賴項.
產品頁面的螢幕截圖:
使用微服務
公共網站應用程式使用Blogging和Product微服務透過公共網站閘道器進行所有操作(PublicWebSiteGateway.Host).
遠端端點
appsettings.json
檔案包含RemoteServices
部分,用於宣告遠端服務端點. 每個微服務通常都有不同的端點. 但是,此解決方案使用API閘道器樣式為應用程式提供單個端點:
http://localhost:64897/
是PublicWebSiteGateway.Host專案的URL. 它知道Blogging和產品服務的位置.
HTTP Clients
PublicWebSiteHostModule
類宣告BloggingHttpApiClientModule
和ProductManagementHttpApiClientModule
的依賴關係,以便能夠為這些服務使用遠端HTTP API.
傳遞訪問令牌(Access Token)
正如後端管理應用程式部分中所述, Public Web Site專案還使用AbpHttpClientIdentityModelModule
將access_token
傳遞給呼叫服務進行身份驗證.
Dependencies
- Redis 用於分散式/共享快取.
- Elasticsearch 用於儲存日誌.
控制檯客戶端演示
最後,該解決方案包括一個非常簡單的控制檯應用程式,名為ConsoleClientDemo,它透過AuthServer進行身份驗證來使用Identity和Product服務. 它使用內部閘道器(InternalGateway.Host)來執行HTTP API呼叫.
遠端服務配置
appsettings.json
檔案中的RemoteService
配置很簡單:
http://localhost:65129/
是內部閘道器的URL. 對服務的所有API呼叫都是透過此URL執行的.
身份驗證(IdentityServer客戶端)配置
appsettings.json
還有一個IdentityServer身份驗證配置:
此示例使用client_credentials
授予型別,該型別需要ClientId
和ClientSecret
進行身份驗證過程. 還有其他授予型別. 例如, 你可以使用以下配置切換到password
(Resource Owner Password)授予型別:
除客戶端憑據外,Resource Owner Password還需要UserName
和 UserPassword
. 此授權型別對於代表使用者呼叫遠端服務很有用.
Scope
宣告API(和閘道器)以授予訪問許可權. 此應用程式使用內部閘道器.
HTTP Client依賴
ConsoleClientDemoModule
與AbpIdentityHttpApiClientModule
和ProductManagementHttpApiClientModule
有依賴關係,以便使用Identity和Product API. 它還具有“AbpHttpClientIdentityModelModule”依賴性,可透過IdentityServer進行身份驗證.
使用服務
使用這些服務非常簡單. 請參閱ClientDemoService
類,它只是註入IIdentityUserAppService
和IProductAppService
並使用它們. 該類還顯示了使用HttpClient
物件的手動HTTP呼叫. 有關詳細資訊,請參閱ClientDemoService
的原始碼.
API閘道器/ BFF(前端後端)
閘道器用於為應用程式提供 單一入口點. 透過這種方式,應用程式僅處理單個服務地址(API端點),而不是每個服務的不同地址. 閘道器還用於速率限制,安全性,身份驗證,負載平衡和更多要求.
“後端前端“(BFF)是一種常見的架構樣式,可為每種不同的應用程式/客戶端型別構建專註而專業的閘道器. 此解決方案使用此樣式並具有多個閘道器.
此解決方案使用Ocelot庫來構建API閘道器. 它是ASP.NET核心廣泛接受的API閘道器庫.
後端管理應用程式閘道器 (BackendAdminAppGateway.Host)
這是”後端管理應用程式”的後端(伺服器端API)(不要混淆命名;後端管理應用程式實際上是前端Web應用程式,但系統管理員而不是普通使用者使用).
認證
此閘道器使用IdentityServer Bearer
身份驗證並配置如下:
AddIdentityServerAuthentication
擴充套件方法來自 IdentityServer4.AccessTokenValidation 包, IdentityServer4專案的一部分 (參見 identityserver檔案).
ApiName
是受保護的API,在這種情況下是BackendAdminAppGateway
. 因此,此解決方案將閘道器定義為API資源. 其餘配置與宣告對映(計劃在下一個ABP版本中自動化)相關. appsettings.json
中的身份驗證相關的配置很簡單:
Ocelot配置
Ocelot需要知道微服務的真實URL才能重定向HTTP請求. 此閘道器的配置如下所示:
ReRoutes
是一個URL對映陣列. GlobalConfiguration
部分中的BaseUrl
是該閘道器的URL(Ocelot需要知道自己的URL). 參見 ocelot檔案 更好地瞭解配置.
Ocelot is a finalizer ASP.NET Core middleware and should be written as the last item in the pipeline:
Ocelot是一個終結ASP.NET核心中介軟體,應該寫成管道中的最後一項:
它根據上面的配置處理和重定向請求.
ABP 配置端點
ABP提供了一些內建API,以從伺服器獲取一些配置和資訊. 例子:
/api/abp/application-configuration
傳回本地化文字,許可權和設定值 (http://localhost:65115/api/abp/application-configuration)./Abp/ServiceProxyScript
傳回動態javascript代理以從javascript客戶端呼叫服務 (http://localhost:65115/Abp/ServiceProxyScript ).
這些端點應由閘道器服務提供,而不是由微服務提供. 微服務只能知道與該微服務相關的許可權. 但是,一旦正確配置,閘道器就可以將多個服務的許可權值聚合為一個更適合客戶端的串列.
為此, ASP.NET Core管道配置為透過MVC而不是Ocelot處理某些特定路由. 為了實現這一點,MapWhen擴充套件方法使用如下:
當請求路徑以 /api/abp/
或 /Abp/
.開頭時,此配置使用標準MVC中介軟體.
Swagger
此閘道器配置為使用swagger UI, 這是一種用於發現和測試HTTP API的流行工具. 通常,Ocelot不支援在swagger上顯示API,因為它無法瞭解每個微服務API的詳細資訊. 但是當你遵循ABP分層模組架構最佳實踐時,它是可能的.
BackendAdminAppGatewayHostModule
將依賴性新增到AbpIdentityHttpApiModule
(Volo.Abp.Identity.HttpApi包)和ProductManagementHttpApiModule
(ProductManagement.HttpApi 專案)以包含它們的HTTP API控制器. 透過這種方式,swagger可以發現它們. 雖然它取用了API層,但它沒有取用應用程式服務的實現,因為它們將在相關的微服務端點中執行,並由Ocelot根據請求URL重定向.
無論如何,當你開啟URLhttp://localhost:65115/swagger/index.html
時, 你將看到所有已配置的微服務的API.
許可權管理
後端管理應用程式提供許可權管理UI(之前見過),並使用此閘道器獲取/設定許可權. 許可權管理API託管在閘道器內,而不是單獨的服務. 這是一個設計決策,但如果您願意,它可以作為另一個微服務託管.
Dependencies
- RabbitMQ 用於向其他服務傳送訊息.
- Redis 用於分散式/共享快取.
- Elasticsearch 用於儲存日誌.
公共網站閘道器 (PublicWebSiteGateway.Host)
這是”公共網站”應用程式的後端(伺服器端API閘道器).
認證
此閘道器使用IdentityServer Bearer
身份驗證並配置如下:
AddIdentityServerAuthentication
擴充套件方法來自 IdentityServer4.AccessTokenValidation包, IdentityServer4專案的一部分 (參見 identityserver檔案).
ApiName
是受保護的API,在這種情況下是PublicWebSiteGateway
. 其餘配置與宣告對映(計劃在下一個ABP版本中自動化)相關. 與appsettings.json
中的身份驗證相關的配置很簡單:
Ocelot配置
Ocelot需要知道微服務的真實URL才能重定向HTTP請求. 此閘道器的配置如下所示:
參見 ocelot檔案 更好地瞭解配置.
其它
請參閱”後端管理應用程式閘道器”部分中的”ABP配置端點”和”Swagger”主題,這些主題與此閘道器非常相似.
依賴
- RabbitMQ 用於向其他服務傳送訊息.
- Redis 用於分散式/共享快取.
- Elasticsearch 用於儲存日誌.
內部閘道器 (InternalGateway.Host)
該閘道器不是BFF. 它專為微服務間通訊而設計,不會公開.
認證
此閘道器使用IdentityServer Bearer
身份驗證並配置如下:
AddIdentityServerAuthentication
擴充套件方法來自 IdentityServer4.AccessTokenValidation包, IdentityServer4專案的一部分 (參見 identityserver檔案).
ApiName
是受保護的API,在這種情況下是InternalGateway
. 其餘配置與宣告對映(計劃在下一個ABP版本中自動化)相關. 與appsettings.json
中的身份驗證相關的配置很簡單:
Ocelot 配置
Ocelot需要知道微服務的真實URL才能重定向HTTP請求. 此閘道器的配置如下所示:
ReRoutes
配置涵蓋了系統中的所有微服務. 參見 ocelot檔案 更好地瞭解配置.
其它
請參閱”後端管理應用程式閘道器”部分中的”ABP配置端點”和”Swagger”主題,這些主題與此閘道器非常相似.
依賴
- RabbitMQ 用於向其他服務傳送訊息.
- Redis 用於分散式/共享快取.
- Elasticsearch 用於儲存日誌.
微服務
微服務是獨立的HTTP API,它們以分散式方式實現系統業務.
- 它們由應用程式和其他微服務透過閘道器和HTTP API使用.
- 他們可以提升或註冊系統中的事件.
- 它們可以透過非同步訊息傳遞相互通訊.
Identity Service (IdentityService.Host)
此服務提供使用者和角色管理API.
資料庫
與AuthServer應用程式共享相同的資料庫(MsDemo_Identity).
Identity模組
該服務實際上只託管ABP身份包/模組. 不包含任何API本身. 為了託管它,新增以下依賴項:
AbpIdentityHttpApiModule
(Volo.Abp.Identity.HttpApi 包) 提供身份API.AbpIdentityApplicationModule
(Volo.Abp.Identity.Application 包)承載模組的應用程式和域層的實現.AbpIdentityEntityFrameworkCoreModule
(Volo.Abp.Identity.EntityFrameworkCore 包) 使用EF Core作為資料庫API.
請參閱module architecture best practice guide以更好地理解分層.
認證
這個微服務使用IdentityServerBearer
身份驗證,並配置如下:
ApiName
是受保護的API,在這種情況下是IdentityService
. 其餘配置與宣告對映(計劃在下一個ABP版本中自動化)相關. 與appsettings.json
中的身份驗證相關的配置很簡單:
Swagger
Swagger UI已配置,是此服務的預設頁面. 如果你導航到URLhttp://localhost:63568/
, 你將被重定向到swagger頁面以檢視和測試API.
依賴
- RabbitMQ 用於向其他服務傳送訊息.
- Redis 用於分散式/共享快取.
- Elasticsearch 用於儲存日誌.
部落格服務 (BloggingService.Host)
此服務託管部落格API.
資料庫
它有一個專門的MongoDB資料庫(MsDemo_Blogging)來儲存部落格和帖子. 它還使用MsDemo_Identity SQL資料庫來審核日誌,許可權和設定. 因此,appsettings.json
檔案中有兩個連線字串:
部落格模組
該服務實際上只託管ABP Blogging包/模組. 不包含任何API本身. 為了託管它,新增以下依賴項:
BloggingHttpApiModule
(Volo.Blogging.HttpApi 包) 提供Blogging API.BloggingApplicationModule
(Volo.Blogging.Application 包) 承載模組的應用程式和域層的實現.BloggingMongoDbModule
(Volo.Blogging.MongoDB 包) 使用MongoDB作為資料庫.
請參閱module architecture best practice guide以更好地理解分層.
認證
這個微服務使用IdentityServer Bearer
身份驗證,並配置如下:
ApiName
是受保護的API,在這種情況下是BloggingService
. 其餘配置與宣告對映(計劃在下一個ABP版本中自動化)相關.與appsettings.json
中的身份驗證相關的配置很簡單:
IdentityServer Client
此微服務還透過內部閘道器使用Identity微服務API, 因為在某些情況下它需要查詢使用者詳細資訊(username, email, phone, name and surname). 因此,它也是IdentityServer的客戶端,併在appsettings.json
檔案中定義了一個部分:
由於它使用內部閘道器, 因此它還應配置閘道器的遠端端點:
當你將UseCurrentAccessToken
設定為false
時,ABP會忽略當前HttpContext
中的當前access_token
,並使用上面定義的憑據對AuthServer進行身份驗證.
為什麼不在當前請求中使用當前使用者的令牌? 因為,使用者可能沒有Identity模組所需的許可權,因此它不能直接將當前身份驗證令牌傳遞給Identity服務. 此外,某些部落格服務API是匿名的(不需要經過身份驗證的使用者),因此在某些情況下,HTTP請求中沒有”當前使用者”. 出於這些原因,應將Blogging服務定義為具有自己的憑據和許可權的Identity服務的客戶端.
如果檢查MsDemo_Identity
資料庫中的AbpPermissionGrants
表,則可以看到blogging-service-client
的相關許可權.
Swagger
Swagger UI已配置,是此服務的預設頁面. 如果你導航到URLhttp://localhost:62157/
, 你將被重定向到swagger頁面以檢視和測試API.
依賴
- RabbitMQ 用於向其他服務傳送訊息.
- Redis 用於分散式/共享快取.
- Elasticsearch 用於儲存日誌.
產品服務 (ProductService.Host)
此服務託管產品管理API.
資料庫和EF核心遷移
它有一個單獨的SQL資料庫,名為MsDemo_ProductManagement,用於產品管理模組. 它使用EF Core作為資料庫提供程式,並具有名為ProductServiceMigrationDbContext
的DbContext:
實際模型配置在modelBuilder.ConfigureProductManagement()
擴充套件方法內完成. 此專案使用EF Core遷移維護資料庫樣式.
請註意,此DbContext僅用於資料庫遷移. Product Management模組有自己的DbContext
類,它在執行時使用(參見ProductManagement.EntityFrameworkCore專案中的ProductManagementDbContext
類).
appsettings.json
檔案中有兩個連線字串:
Default
連線字串指向MsDemo_Identity資料庫,該資料庫用於審計日誌記錄,許可權和設定儲存. 產品模組使用ProductManagement
連線字串.
產品模組
該服務實際上只託管產品管理模組. 不包含任何API本身. 為了託管它,新增以下依賴項:
ProductManagementHttpApiModule
提供產品管理API.ProductManagementApplicationModule
承載模組的應用程式和域層的實現.ProductManagementEntityFrameworkCoreModule
使用EF Core作為資料庫API.
請參閱module architecture best practice guide以更好地理解分層. 有關此模組的更多資訊,請參閱下麵的”產品管理”模組部分
認證
這個微服務使用IdentityServer Bearer
身份驗證,並配置如下:
ApiName
是受保護的API,在這種情況下是ProductService
. 其餘配置與宣告對映(計劃在下一個ABP版本中自動化)相關. 與appsettings.json
中的身份驗證相關的配置很簡單:
Swagger
Swagger UI已配置,是此服務的預設頁面. 如果你導航到URLhttp://localhost:60244/
, 你將被重定向到swagger頁面以檢視和測試API.
依賴
- RabbitMQ 用於向其他服務傳送訊息.
- Redis 用於分散式/共享快取.
- Elasticsearch 用於儲存日誌.
模組
ABP提供強大的基礎架構,透過提供服務和架構,使模組化應用程式開發更容易(參見模組開發最佳實踐指南).
此解決方案演示瞭如何在分散式體系結構中使用預構建的應用程式模組. 該解決方案還包括一個簡單的”產品管理”模組,用於顯示分層模組示例的實現.
產品管理
產品管理是一個由多個層和包/專案組成的模組:
-
ProductManagement.Domain.Shared
包含所有層之間共享的常量和型別. -
ProductManagement.Domain
包含域邏輯並定義物體,域服務,域事件,業務/域異常. -
ProductManagement.Application.Contracts
包含應用程式服務介面和DTO. -
ProductManagement.Application
包含應用程式服務的實現. -
ProductManagement.EntityFrameworkCore
包含DbContext和其他與EF Core相關的類和配置. -
ProductManagement.HttpApi
包含API控制器. -
ProductManagement.HttpApi.Client
包含C#代理以遠端直接使用HTTP API. 使用ABP的Dynamic C#API客戶端功能. -
ProductManagement.Web
包含UI元素(頁面,指令碼,樣式..等).
透過此分層的幫助,可以在單個應用程式中使用相同的模組作為包取用,或者用作在另一個伺服器中執行的服務. 可以分離UI(Web)和API層,因此它們可以在不同的伺服器中執行.
在此解決方案中,Web層在後端管理應用程式中執行,而API層由產品微服務託管.
本教程將重點介紹該模組的一些重要方面. 但是,建議檢視原始碼以便更好地理解.
Domain Layer
Product
是這個模組的主要聚合根:
它的所有屬性都有私有的set方法,可以防止屬性從類中直接更改. 產品類透過自己的建構式和方法確保其自身的完整性和有效性.
它有兩個建構式:
預設(無引數)建構式是私有的,不在應用程式程式碼中使用. 這是必需的,因為大多數ORM在從資料庫獲取時需要在反序列化物體時使用無引數建構式.
第二個建構式是internal,這意味著它只能在域層內使用. 這強制在建立新的Product
時使用ProductManager
. 因為“ProductManager`應該在新產品建立上實現業務規則. 此建構式僅需要最少的必需引數來建立具有一些可選引數的新產品. 它會檢查一些簡單的業務規則,以確保將物體建立為有效產品.
該類的其餘部分具有操縱物體屬性的方法. 例:
SetPrice
方法用於以安全的方式更改產品的價格(透過檢查驗證規則).
SetStockCount
是另一種用於更改產品庫存數量的方法:
此方法還觸發分散式事件,其中帶有ProductStockCountChangedEto
引數(Eto是傳統的字尾代表Event Transfer Object,但不是必需的)通知產品庫存數量的聽眾已發生變化. 任何訂戶都可以接收此事件並根據該知識執行操作.
RabbitMQ為此解決方案分發事件. 但是ABP透過提供必要的抽象來獨立於訊息代理Event Bus檔案).
如前所述,該模組強制始終使用ProductManager
來建立新的Product
. ProductManager
是一個簡單的域服務,定義如下:
- 它檢查之前是否使用過給定的程式碼. 否則丟擲
ProductCodeAlreadyExistsException
. - 使用
GuidGenerator
(IGuidGenerator
)服務來建立一個新的Guid
. - 它將物體插入儲存庫.
因此,透過這種設計,產品程式碼的唯一性得到保證.
ProductCodeAlreadyExistsException
是一個域/業務異常,定義如下:
PM:000001
是傳送給客戶端的異常型別的程式碼,因此他們可以理解錯誤型別. 在這種情況下沒有實現,但也可以本地化業務異常. 請參閱異常處理檔案.
應用層
該模組的應用層有兩個服務:
ProductAppService
主要由後端管理應用程式用於管理(建立,更新,刪除.)產品. 它需要許可才能執行任何操作.- 公共網站使用
PublicProductAppService
來向訪問者顯示產品串列. 它不需要任何許可權,因為大多數訪問者都沒有登入到應用程式.
請註意; 每個應用程式分離應用程式層可能是更好的原則, 而不是將兩個應用程式服務放入同一個專案中. 但是我們在這個解決方案中簡化了它們.
例如,ProductAppService
具有以下更新產品的方法:
- 它定義了所需的許可權(ProductManagementPermissions.Products.Update是一個值為
ProductManagement.Update
的常量)來執行此操作. - 獲取產品的ID,DTO包含要更新的值.
- 從儲存庫中獲取相關的產品物體.
- 使用
Product
類的相關方法(如SetName
)來更改屬性,因為它們是私有set方法,更改值的唯一方法是使用物體方法. - 透過使用ObjectMapper向客戶端傳回更新的
ProductDto
(客戶端可能由於某種原因需要它).
實施可能會根據要求而有所不同. 此實現遵循此處提供的最佳實踐.
其他層
請參閱原始碼中的其他層.
基礎設施
訊息和RabbitMQ
非同步訊息傳遞是分散式系統中的關鍵概念. 它可以以鬆散耦合的方式與容錯進行通訊. 在傳送訊息時,它不要求雙方都線上. 因此,它是微服務架構中廣泛使用的通訊樣式.
分散式事件匯流排
分散式事件(事件匯流排)是一種訊息傳遞方式,其中服務引發/觸發事件,而其他服務註冊/偵聽這些事件,以便在發生重要事件時得到通知. ABP透過提供約定,服務和整合使分散式事件更易於使用.
您已經看到Product
類使用以下程式碼行釋出事件:
ProductStockCountChangedEto
was defined as shown below:
該物件儲存有關該事件的必要資訊. 透過使用通用的ProductStockCountChangedEto
引數實現IDistributedEventHandler
介面,另一個服務可以輕鬆註冊到此事件:
當你使用Volo.Abp.EventBus.RabbitMQ包時,所有整合和通訊都由ABP框架完成.如果需要從物體釋出事件,只需註入IDistributedEventBus
並使用PublishAsync
方法.
有關分散式事件系統的更多資訊, 請參見Event Bus檔案.
RabbitMQ配置
在此解決方案中, RabbitMQ用於訊息傳遞和分散式事件.
Volo.Abp.EventBus.RabbitMQ包需要整合到RabbitMQ以用於分散式事件系統. 然後你需要為模組的AbpEventBusRabbitMqModule
新增依賴項. 例如ProductServiceHostModule
宣告了這種依賴.
預設情況下,abpEventBusRabbitMqModule
從appsettings.json
獲取配置. 例如產品服務具有以下配置:
快取和Redis
分散式系統顯然需要分散式和共享快取,而不是每個服務的隔離記憶體快取.
Redis在此解決方案中用作分散式快取. 該解決方案使用Microsoft的標準Microsoft.Extensions.Caching.Redis包進行整合. 使用和配置此程式包時,所有應用程式和服務都使用Redis快取. 有關詳細資訊請參閱Microsoft的檔案.
該解決方案還使用Microsoft.AspNetCore.DataProtection.StackExchangeRedis包在Redis快取上共享應用程式和服務之間的資料保護金鑰.
Logging,Serilog,Elasticsearch和Kibana
該解決方案使用Serilog作為日誌庫. 它是一個廣泛使用的庫,有許多資料源整合,包括Elasticsearch.
使用類似於下麵給出的程式碼塊在Program.cs
檔案中完成日誌配置:
這會配置多個日誌輸出標的:File和Elasticsearch.對於此示例,Application
屬性設定為ProductService
. 這是一種區分單個資料庫中多個服務的日誌的方法. 然後, 你可以透過Application
名稱查詢日誌.
從appsettings.json
配置檔案中讀取Elasticsearch URL:
如果你使用Kibana, 它是一個與Elasticsearch完美整合的視覺化工具,可以看到有關你的日誌的一些UI:
Figure – 一個儀錶板,顯示服務/應用程式的日誌和錯誤計數.
Figure – 日誌條目串列
Kibana URL預設為http://localhost:5601/
.
審計日誌
ABP提供自動審計日誌記錄,詳細儲存每個請求(當前使用者,瀏覽器/客戶端,執行了哪些操作,哪些物體更改,甚至物體的哪些屬性已更新). 有關詳細資訊,請參閱審計日誌檔案.
所有服務和應用程式都配置為編寫審核日誌. 審核日誌將儲存到MsDemo_Identity SQL資料庫中. 因此,您可以從單個點查詢所有應用程式的所有審核日誌.
審核日誌記錄具有CorrelationId
屬性,可用於跟蹤請求. 當服務在單個Web請求中呼叫另一個服務時,它們都會使用相同的CorrelationId
儲存審核日誌. 請參閱資料庫中的AbpAuditLogs
表.
原文地址:https://cn.abp.io/documents/abp/latest/Samples/Microservice-Demo