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-serverhosts文件位于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
.NET社區新聞,深度好文,歡迎訪問公眾號文章匯總 http://www.csharpkit.com
總結
以上是生活随笔為你收集整理的ASP.NET Core开源Web应用程序框架ABP的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ASP.NET Core应用程序容器化、
- 下一篇: ASP.NET Core 借助 K8S