歡迎光臨
每天分享高質量文章

ASP.NET Core開源Web應用程式框架ABP

“作為面向服務架構(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.zipMsDemo_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_BloggingMongoDB資料庫. 由BloggingService使用.
  • Elasticsearch: 用於在Serilog上寫日誌.

應用

認證服務器 (AuthServer.Host)

所有其他服務和應用程式都使用此專案進行身份驗證和單點登錄. 主要使用IdentityServer4來提供這些服務. 它使用了一些預構建ABP模塊 如 IdentityAudit 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) roleemail and phone.
  • It requires the API resource scopes BackendAdminAppGatewayIdentityService and ProductServicebecause it will use these services as APIs.
  • 它需要API資源範圍 BackendAdminAppGatewayIdentityService 和 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類宣告了AbpIdentityHttpApiClientModuleProductManagementHttpApiClientModule的依賴關係.

一旦取用這些客戶端軟體包,就可以直接註入應用程式服務接口(例如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應用程式作為身份驗證服務器.
  • 它需要額外的身份範圍 roleemail and phone.
  • 它需要API資源範圍 PublicWebSiteGateway,BloggingServiceProductService,因為它將這些服務用作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類宣告BloggingHttpApiClientModuleProductManagementHttpApiClientModule的依賴關係,以便能夠為這些服務使用遠程HTTP API.

傳遞訪問令牌(Access Token)

正如後端管理應用程式部分中所述, Public Web Site專案還使用AbpHttpClientIdentityModelModuleaccess_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 授予型別,該型別需要ClientIdClientSecret進行身份驗證過程. 還有其他授予型別. 例如, 你可以使用以下配置切換到password(Resource Owner Password)授予型別:

除客戶端憑據外,Resource Owner Password還需要UserName 和 UserPassword. 此授權型別對於代表用戶呼叫遠程服務很有用.

Scope 宣告API(和網關)以授予訪問權限. 此應用程式使用內部網關.

HTTP Client依賴

ConsoleClientDemoModuleAbpIdentityHttpApiClientModuleProductManagementHttpApiClientModule有依賴關係,以便使用Identity和Product API. 它還具有“AbpHttpClientIdentityModelModule”依賴性,可通過IdentityServer進行身份驗證.

使用服務

使用這些服務非常簡單. 請參閱ClientDemoService類,它只是註入IIdentityUserAppServiceIProductAppService並使用它們. 該類還顯示了使用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來創建新的ProductProductManager是一個簡單的域服務,定義如下:

  • 它檢查之前是否使用過給定的代碼. 否則丟擲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宣告了這種依賴.

預設情況下,abpEventBusRabbitMqModuleappsettings.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

赞(0)

分享創造快樂