參考:
abp官網的文檔:微服務解決方案示例 (注意,要配合文檔去運行項目,然后反復、認真看文檔,文檔中已經把項目的細節講得足夠清楚的了,包含:項目引用、依賴、遠程調用過程、通信、網關等等)
有大佬為abp的微服務項目進行了講解和擴展:[Abp vNext微服務實踐] - 文章目錄----一曲肝腸斷錄
下載ABP全部示例代碼
ABP示例github下載地址,默認是master,也可以選擇最新的版本
ABP微服務架構簡略圖
問題
MongoDb
問題:BloggingService.Host(博客服務)運行失敗,提示MongoDb單台服務器不支持事務,目前我下載的是abp3.2.1版本。說明文檔中的MongoDB中提到新版本好像已經解決這個問題,不過微服務示例還沒有升級到最新版。
雖然有個服務運行失敗,而且我也沒安裝ElasticSearch、Kibana,但項目還是能夠運行起來演示products的效果。
RabbitMQ
問題:目前使用的是3.2.1版本的,發現停止RabbitMQ服務和注釋RabbitMQ代碼都能正常演示
結論:這個ABP微服務示根本就沒有使用RabbitMQ進行消息通信,只不過是有幾個項目有引入RabbitMQ模塊但是沒有使用,微服務示例文檔中居然說是使用RabbitMQ通信的,有點誤導人。
應該是使用 動態 C# API 客戶端 來通信的
項目結構
調用順序:applications(應用層),項目引用:modules(模塊層)、shared(共享層) =》gateways(網關 / 前端后端層) =》microservices(微服務層)
applications(應用層):控制台應用程序 + UI + 身份認證
這些是具有用戶界面以與用戶交互並使用系統的實際應用程序.
- AuthServer.Host 44399: 托管IdentityServer4以向其他服務和應用程序提供身份驗證服務. 它是一個單點登錄服務器,包含登錄頁面.
-
BackendAdminApp.Host 44354: 這是一個后端管理應用程序,用於托管身份和產品管理模塊的UI.
-
PublicWebSite.Host 44335: 作為包含簡單產品列表頁面和博客模塊UI的公共網站.
-
ConsoleClientDemo: 一個簡單的控制台應用程序,用於演示C#應用程序中使用服務.
gateways(網關 / 前端后端層):控制台應用程序 + 網關 + 通信
網關用於為應用程序提供單一入口點.它還可以用於速率限制,負載平衡等. 使用Ocelot類庫.
- BackendAdminAppGateway.Host 44315: 由BackendAdminApp.Host應用程序用作后端.
-
PublicWebSiteGateway.Host 44397: 由PublicWebSite.Host應用程序用作后端.
-
InternalGateway.Host 44329: 用於服務間通信(微服務之間的通信).
microservices(微服務層):控制台應用程序 RabbitMQ + 身份認證 + EFCore
微服務沒有UI,但暴露了一些REST API.
- IdentityService.Host 44368: 托管用於管理用戶和角色的ABP Identity模塊. 它沒有其他服務,僅托管Identity模塊的API.
-
TenantManagementService.Host 44336: 托管用於管理角色的ABP租戶管理模塊. 它沒有其他服務,僅托管租戶管理模塊的API.
-
BloggingService.Host 44357: 托管ABP博客模塊,該模塊用於管理博客和帖子(典型的博客應用程序). 它沒有其他服務,僅托管Blogging模塊的API.
-
ProductService.Host 44344: 托管用於管理產品的產品模塊(位於解決方案內). 它還包含用於創建/更新產品管理數據庫架構的EF Core遷移.
modules(模塊層):類庫 + DDD + DTO + 實體類
項目名稱都是帶有 Management 字眼的
包含基於DDD原則分層的實際模塊:
產品: 使用模塊開發最佳實踐開發的分層模塊. 它可以嵌入到單個應用程序中,也可以通過單獨部署API和UI作為微服務托管
- 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元素(頁面,腳本,樣式..等).
shared(共享層):類庫
-
MsDemo.Shared:多租戶
項目引用
從項目結構看項目引用
其他項目都項目引用modules(名稱帶有Management )、shared(名稱帶有shared)
modules內的product的項目引用關系
ProductManagement.Domain.Shared:沒有項目引用
ProductManagement.Domain:項目引用 ProductManagement.Domain.Shared
ProductManagement.EntityFrameworkCore:項目引用 ProductManagement.Domain
ProductManagement.Application.Contracts:項目引用 ProductManagement.Domain.Shared
ProductManagement.HttpApi.Client:項目引用 ProductManagement.Application.Contracts
ProductManagement.HttpApi:項目引用 ProductManagement.Application.Contracts
ProductManagement.Web:項目引用 ProductManagement.HttpApi
ProductManagement.Application:項目引用 ProductManagement.Domain、ProductManagement.Application.Contracts
通信方式
說明:消息和RabbitMQ
參考:[Abp vNext微服務實踐] - 服務通訊 [Abp vNext 源碼分析] - 13. 本地事件總線與分布式事件總線 (Rabbit MQ)
動態 C# API 客戶端
分布式 Event Bus--里面有說道ABP繼承RabbitMQ
所有示例--里面有2個RabbitMQ的示例的
ABP可以動態創建C#API客戶端代理來調用您的遠程HTTP服務(REST API)。這樣,您無需處理HttpClient
其他低級詳細信息即可調用遠程服務並獲得結果。
動態C#代理會自動為您處理以下內容;
- 通過考慮HTTP方法,路由,查詢字符串參數,請求有效負載和其他詳細信息,將C#方法調用映射到遠程服務器HTTP調用。
- 通過將訪問令牌添加到HTTP標頭來認證HTTP客戶端。
- 從JSON序列化和反序列化。
- 處理HTTP API版本控制。
- 將相關性ID,當前租戶ID和當前區域性添加到請求中。
- 正確處理服務器發送的錯誤消息並引發適當的異常。
任何類型的.NET客戶端都可以使用此系統來使用您的HTTP API。
模塊層的ProductManagement.HttpApi.Client類庫中的模塊類ProductManagementHttpApiClientModule中
- using Volo.Abp.Http.Client
- 模塊依賴typeof(AbpHttpClientModule)
- 使用添加Http客戶端代理方法:AddHttpClientProxies(typeof(ProductManagementApplicationContractsModule).Assembly, RemoteServiceName)
應用程序層
AuthServer.Host:登錄認證服務
- appsettings.json
- RabbitMQ
- Connections
- EventBus,備注:模塊類加載模塊的DependsOn(typeof(AbpEventBusRabbitMqModule))時,AbpEventBusRabbitMqModule類會默認加載配置文件中的RabbitMQ:EventBus信息,反編譯查看AbpEventBusRabbitMqModule的源碼如下:
public class AbpEventBusRabbitMqModule : AbpModule { public override void ConfigureServices(ServiceConfigurationContext context) { IConfiguration configuration = context.Services.GetConfiguration(); Configure<AbpRabbitMqEventBusOptions>(configuration.GetSection("RabbitMQ:EventBus")); } public override void OnApplicationInitialization(ApplicationInitializationContext context) { context.ServiceProvider.GetRequiredService<RabbitMqDistributedEventBus>().Initialize(); } }
- RabbitMQ
PublicWebSite.Hos:產品、博客展示服務
- appsettings.json
- 登錄服務:AuthServer:44399
- 網關:RemoteServices:44397 PublicWebSiteGateway.Host(由PublicWebSite.Host應用程序用作后端)
- AuthServerHostModule
- options.Scope.Add("PublicWebSiteGateway"); //網關
- options.Scope.Add("ProductService"); //產品微服務
- options.Scope.Add("BloggingService"); //博客微服務
Program類讀取配置文件:
- AddJsonFile("appsettings.json")加載配置文件
using System; using System.IO; using System.Linq; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Hosting; using Serilog; using Serilog.Events; using Serilog.Sinks.Elasticsearch; namespace AuthServer.Host { public class Program { public static int Main(string[] args) { //TODO: Temporary: it's not good to read appsettings.json here just to configure logging var configuration = new ConfigurationBuilder() .SetBasePath(Directory.GetCurrentDirectory()) .AddJsonFile("appsettings.json") .AddEnvironmentVariables() .Build(); Log.Logger = new LoggerConfiguration() .MinimumLevel.Debug() .MinimumLevel.Override("Microsoft", LogEventLevel.Information) .MinimumLevel.Override("Microsoft.EntityFrameworkCore", LogEventLevel.Warning) .Enrich.WithProperty("Application", "AuthServer") .Enrich.FromLogContext() .WriteTo.File("Logs/logs.txt") .WriteTo.Elasticsearch( new ElasticsearchSinkOptions(new Uri(configuration["ElasticSearch:Url"])) { AutoRegisterTemplate = true, AutoRegisterTemplateVersion = AutoRegisterTemplateVersion.ESv6, IndexFormat = "msdemo-log-{0:yyyy.MM}" }) .CreateLogger(); try { Log.Information("Starting AuthServer.Host."); CreateHostBuilder(args).Build().Run(); return 0; } catch (Exception ex) { Log.Fatal(ex, "AuthServer.Host terminated unexpectedly!"); return 1; } finally { Log.CloseAndFlush(); } } internal static IHostBuilder CreateHostBuilder(string[] args) => Microsoft.Extensions.Hosting.Host.CreateDefaultBuilder(args) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); }) .UseAutofac() .UseSerilog(); } }
跟蹤調試查看configuration=》Providers=》[0]=>Data,發現Data是一個字典類型的集合:System.Collections.Generic.IDictionary<string, string>
網關層
PublicWebSiteGateway.Host:產品、博客網關
- appsettings.json
- 登錄服務:AuthServer:44399 登錄頁
- 路由:ReRoutes
- DownstreamPathTemplate(下游路徑模板):productManagement?模塊層?還是模板
- DownstreamScheme(下游服務協議:http/https):
- DownstreamHostAndPorts(下游服務地址):指定對應微服務
- UpstreamPathTemplate(上游路徑模板):
- UpstreamHttpMethod(上游HTTP方法):[ "Put", "Delete", "Get", "Post" ]
- PublicWebSiteGatewayHostModule模塊類
-
//讀取appsettings.json文件的登錄配置 context.Services.AddAuthentication("Bearer") .AddIdentityServerAuthentication(options => { options.Authority = configuration["AuthServer:Authority"]; options.ApiName = configuration["AuthServer:ApiName"]; options.RequireHttpsMetadata = false; }); //Ocelot網關 context.Services.AddOcelot(context.Services.GetConfiguration()); app.UseOcelot().Wait();
-
微服務層
ProductService.Host:產品微服務
- appsettings.json
- 登錄服務:AuthServer:44399 =》登錄頁
BloggingService.Host:博客微服務
- appsettings.json
- 登錄服務:AuthServer:44399 =》登錄頁
- 網關:RemoteServices:44329 =》InternalGateway.Host : 用於服務間通信(微服務之間的通信)
- 認證:IdentityClients:4439 =》登錄頁