1. 服務創建
聚合服務層是基礎服務層的封裝及聚合,只需要提供對外WebAPI接口,不需要提供數據庫訪問和領域對象。所以我們只需要創建Host、Application和Application.Contracts即可。
這里我們以商城服務為例在總解決方案下創建application文件夾用於存放所有層代碼,並創建子文件夾store,用於存放商城服務所有代碼。
在總項目解決方案文件夾中添加解決方案文件夾與上一步目錄結構相同。
在總項目解決方案中添加空白項目Demo.Store.HttpApi.Host和類庫項目Demo.Store.Application及Demo.Store.Application.Contracts
添加引用關系:Demo.Store.HttpApi.Host引用Demo.Store.Application,Demo.Store.Application引用Demo.Store.Application.Contracts
添加完成后項目結構如下:
2. 基礎配置
為Demo.Store.Application.Contracts項目添加Nuget依賴:Volo.Abp.Ddd.Application.Contracts
為Demo.Store.Application.Contracts項目添加類DemoStoreApplicationContractsModule代碼如下:
using Volo.Abp.Application; using Volo.Abp.Modularity; namespace Demo.Store.Application.Contracts; [DependsOn(typeof(AbpDddApplicationContractsModule))] public class DemoStoreApplicationContractsModule : AbpModule { }
為Demo.Store.Application項目添加Nuget依賴:Volo.Abp.Ddd.Application、Volo.Abp.AutoMapper
為Demo.Store.Application項目添加類DemoStoreApplicationModule代碼如下:
using Demo.Store.Application.Contracts; using Microsoft.Extensions.DependencyInjection; using Volo.Abp.Application; using Volo.Abp.AutoMapper; using Volo.Abp.Modularity; namespace Demo.Store.Application; [DependsOn(typeof(AbpDddApplicationModule))] [DependsOn(typeof(DemoStoreApplicationContractsModule))] [DependsOn(typeof(AbpAutoMapperModule))] public class DemoStoreApplicationModule:AbpModule { public override void ConfigureServices(ServiceConfigurationContext context) { context.Services.AddAutoMapperObjectMapper<DemoStoreApplicationModule>(); Configure<AbpAutoMapperOptions>(options => { options.AddMaps<DemoStoreApplicationModule>(validate: false); }); } }
為Demo.Store.HttpApi.Host項目添加Nuget依賴:Serilog.AspNetCore、Serilog.Sinks.Async、Volo.Abp.AspNetCore.Mvc、Volo.Abp.Autofac、Volo.Abp.Swashbuckle
為Demo.Store.HttpApi.Host項目添加類DemoStoreHttpApiHostModule代碼如下:
using Demo.Store.Application; using Microsoft.OpenApi.Models; using Volo.Abp; using Volo.Abp.AspNetCore.Mvc; using Volo.Abp.Autofac; using Volo.Abp.Modularity; using Volo.Abp.Swashbuckle; namespace Demo.Store.HttpApi.Host; [DependsOn(typeof(AbpAspNetCoreMvcModule))] [DependsOn(typeof(AbpAutofacModule))] [DependsOn(typeof(DemoStoreApplicationModule))] [DependsOn(typeof(AbpSwashbuckleModule))] public class DemoStoreHttpApiHostModule : AbpModule { public override void ConfigureServices(ServiceConfigurationContext context) { Configure<AbpAspNetCoreMvcOptions>(options => { options .ConventionalControllers .Create(typeof(DemoStoreApplicationModule).Assembly); }); context.Services.AddAbpSwaggerGen( options => { options.SwaggerDoc("v1", new OpenApiInfo { Title = "Store API", Version = "v1" }); options.DocInclusionPredicate((docName, description) => true); options.CustomSchemaIds(type => type.FullName); } ); } public override void OnApplicationInitialization(ApplicationInitializationContext context) { var app = context.GetApplicationBuilder(); var env = context.GetEnvironment(); if (env.IsDevelopment()) { app.UseExceptionHandler("/Error"); } app.UseSwagger(); app.UseAbpSwaggerUI(options => { options.SwaggerEndpoint("/swagger/v1/swagger.json", "Test API"); }); app.UseStaticFiles(); app.UseRouting(); app.UseConfiguredEndpoints(); } }
修改Demo.Store.HttpApi.Host項目Program類如下:
using Demo.Store.HttpApi.Host; using Serilog; using Serilog.Events; Log.Logger = new LoggerConfiguration() #if DEBUG .MinimumLevel.Debug() #else .MinimumLevel.Information() #endif .MinimumLevel.Override("Microsoft", LogEventLevel.Information) .Enrich.FromLogContext() .WriteTo.Async(c => c.File("Logs/logs.txt")) #if DEBUG .WriteTo.Async(c => c.Console()) #endif .CreateLogger(); var builder = WebApplication.CreateBuilder(args); builder.Host.UseAutofac().UseSerilog(); builder.Services.ReplaceConfiguration(builder.Configuration); builder.Services.AddApplication<DemoStoreHttpApiHostModule>(); var app = builder.Build(); app.InitializeApplication(); app.Run();
為Demo.Store.HttpApi.Host項目配置文件appsettings.json增加如下配置
"urls": "http://*:6002"
運行Demo.Store.HttpApi.Host項目並訪問http://localhost:6002/swagger/index.html可正常顯示Swagger頁面即添加成功
3.添加動態客戶端代理
ABP vNext框架提供了動態代理機制,詳見:https://docs.abp.io/en/abp/latest/API/Dynamic-CSharp-API-Clients
這里我們的我們的商城服務依賴訂單管理和商品管理兩個微服務
因為ABP框架通過CLI命令拉取的模板已包含API調用的動態客戶端代理封裝,即HttpAPi.Client項目,我們這里只需要為Demo.Store.Application項目添加Demo.OrderManager.HttpApi.Client和Demo.ProductManager.HttpApi.Client的項目引用並在DemoStoreApplicationModule類中添加DependOn特性如下:
[DependsOn(typeof(OrderManagerHttpApiClientModule),typeof(ProductManagerHttpApiClientModule))]
之后我們需要在Demo.Store.HttpApi.Host項目的配置文件appsettings.json中添加兩個服務的地址配置如下:
"RemoteServices": { "ProductManager": { "BaseUrl": "http://localhost:5010/" }, "OrderManager": { "BaseUrl": "http://localhost:5011/" } }
4.接口開發
在Demo.Store.Application.Contracts項目下添加Store文件夾並在其下添加Dto子文件夾
在Dto文件夾下添加數據傳輸對象,這里以添加訂單服務接口為例,依次添加StoreProductCountDto與StoreOrderCreateDto類如下:
using System.ComponentModel.DataAnnotations; namespace Demo.Store.Application.Contracts.Store.Dto; /// <summary> /// 產品數量DTO /// </summary> public record StoreProductCountDto { /// <summary> /// 產品編號 /// </summary> public Guid ProductId { get; set; } /// <summary> /// 數量 /// </summary> [Range(1, 100000)] public int Count { get; set; } }
namespace Demo.Store.Application.Contracts.Store.Dto; /// <summary> /// 創建訂單DTO /// </summary> public class StoreOrderCreateDto { /// <summary> /// 參考號 /// </summary> public string ReferenceNo { get; init; } /// <summary> /// 訂單商品列表 /// </summary> public List<StoreProductCountDto> Products { get; init; } }
在Demo.Store.Application.Contracts項目Store文件夾下添加應用服務接口IStoreOrderAppService如下:
using Volo.Abp.Application.Services; namespace Demo.Store.Application.Contracts.Store; /// <summary> /// 商城訂單應用服務接口 /// </summary> public interface IStoreOrderAppService : IApplicationService { /// <summary> /// 創建訂單 /// </summary> /// <param name="input">輸入對象</param> /// <returns>創建結果</returns> Task<bool> CreateAsync(StoreOrderCreateDto input); }
在Demo.Store.Application項目添加Store文件夾
在Demo.Store.Application項目Store文件夾中添加StoreAutoMapperProfile類用於存放該領域映射關系如下:
using Demo.OrderManager.Orders.Dto; using Demo.ProductManager.Products.Dto; using Demo.Store.Application.Contracts.Store.Dto; using Volo.Abp.AutoMapper; namespace Demo.Store.Application; public static class StoreAutoMapperProfile { /// <summary> /// 創建商城領域映射關系 /// </summary> /// <param name="profile"></param> public static void CreateStoreMap(this DemoStoreApplicationAutoMapperProfile profile) { profile.CreateMap<StoreOrderCreateDto, OrderCreateDto>() .Ignore(x=>x.Products) .AfterMap((source, target) => { target.Products = new List<ProductCountDto>(); foreach (var productCount in source.Products) { target.Products.Add(new ProductCountDto(productCount.ProductId, productCount.Count)); } }); } }
在Demo.Store.Application項目中添加總映射關系類DemoStoreApplicationAutoMapperProfile如下:
using AutoMapper; namespace Demo.Store.Application; public class DemoStoreApplicationAutoMapperProfile : Profile { public DemoStoreApplicationAutoMapperProfile() { this.CreateStoreMap(); } }
在Demo.Store.Application項目Store文件夾中添加應用服務實現類StoreOrderAppService如下:
using Demo.OrderManager.Orders; using Demo.OrderManager.Orders.Dto; using Demo.ProductManager.Products; using Demo.ProductManager.Products.Dto; using Demo.Store.Application.Contracts.Store; using Demo.Store.Application.Contracts.Store.Dto; using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Services; namespace Demo.Store.Application; /// <summary> /// 訂單管理應用服務 /// </summary> public class StoreOrderAppService : ApplicationService, IStoreOrderAppService { private IOrderAppService _orderAppService; private IProductAppService _productAppService; public StoreOrderAppService(IOrderAppService orderAppService, IProductAppService productAppService) { _orderAppService = orderAppService; _productAppService = productAppService; } /// <summary> /// 創建訂單 /// </summary> /// <param name="input">輸入對象</param> /// <returns>創建結果</returns> public async Task<bool> CreateAsync(StoreOrderCreateDto input) { foreach (var item in input.Products) { //判斷是否為有效的產品ID _productAppService.GetAsync(item.ProductId); } var order = ObjectMapper.Map<StoreOrderCreateDto, OrderCreateDto>(input); var ret = await _orderAppService.CreateAsync(order); return ret != null; } }
添加完成后啟動商城服務、產品管理服務和訂單管理三個服務。訪問http://localhost:6002/swagger/index.html並測試/api/app/store-order(POST)接口,可創建訂單表示服務編寫成功。
以相同方式完成該服務其他接口編寫。
以相同方式編寫后台管理服務用於對外提供對用戶角色的管理接口。