OnionArch - 采用DDD+CQRS+.Net 7.0實現的洋蔥架構( 三 )

8.GRPC Message做為業務用例實體通過將GRPC proto文件放入Application項目,重用其生成的message作為業務用例實體(Model) 。
public class AddCategoryCommand : ICommand{public AddCategoryRequest Model { get; set; }}其中AddCategoryRequest 為proto生成的message 。
9.通用CURD業務用例在應用層分別實現了CURD的Command(增改刪)和Query(查詢) Handler 。

OnionArch - 采用DDD+CQRS+.Net 7.0實現的洋蔥架構

文章插圖
OnionArch - 采用DDD+CQRS+.Net 7.0實現的洋蔥架構

文章插圖
public class CUDCommandHandler<TModel, TEntity> : IRequestHandler<CUDCommand<TModel>> where TEntity : BaseEntity{private readonly CURDDomainService<TEntity> _curdDomainService;public CUDCommandHandler(CURDDomainService<TEntity> curdDomainService){_curdDomainService = curdDomainService;}public async Task<Unit> Handle(CUDCommand<TModel> request, CancellationToken cancellationToken){TEntity entity = null;if (request.Operation == "C" || request.Operation == "U"){if (request.Model == null){throw new BadRequestException($"the model of this request is null");}entity = request.Model.Adapt<TEntity>();if (entity == null){throw new ArgumentNullException($"the entity of {nameof(TEntity)} is null");}}if (request.Operation == "U" || request.Operation == "D"){if (request.Id == Guid.Empty){throw new BadRequestException($"the Id of this request is null");}}switch (request.Operation){case "C":await _curdDomainService.Create(entity);break;case "U":await _curdDomainService.Update(entity);break;case "D":await _curdDomainService.Delete(request.Id);break;}return Unit.Value;}}開發人員只需要在GRPC層簡單調用即可實現CURD業務 。
public async override Task<AddProductReply> AddProduct(AddProductRequest request, ServerCallContext context){CUDCommand<AddProductRequest> addProductCommand = new CUDCommand<AddProductRequest>();addProductCommand.Id = Guid.NewGuid();addProductCommand.Model = request;addProductCommand.Operation = "C";await _mediator.Send(addProductCommand);return new AddProductReply(){Message = "Add Product sucess"};}10. 業務實體驗證通過FluentValidation和MediatR 管道實現業務實體自動驗證,并自動拋出自定義異常 。
OnionArch - 采用DDD+CQRS+.Net 7.0實現的洋蔥架構

文章插圖
OnionArch - 采用DDD+CQRS+.Net 7.0實現的洋蔥架構

文章插圖
public class RequestValidationBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse> where TRequest : IRequest<TResponse>{private readonly IEnumerable<IValidator<TRequest>> _validators;public RequestValidationBehavior(IEnumerable<IValidator<TRequest>> validators){_validators = validators;}public async Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<TResponse> next){var errors = _validators.Select(v => v.Validate(request)).SelectMany(result => result.Errors).Where(error => error != null).ToList();if (errors.Any()){var errorBuilder = new StringBuilder();errorBuilder.AppendLine("Invalid Request, reason: ");foreach (var error in errors){errorBuilder.AppendLine(error.ErrorMessage);}throw new InvalidRequestException(errorBuilder.ToString(), null);}return await next();}}開發人員只需要定義驗證規則即可
public class AddCategoryCommandValidator : AbstractValidator<AddCategoryCommand>{public AddCategoryCommandValidator(){RuleFor(x => x.Model.CategoryName).NotEmpty().WithMessage(p => "類別名稱不能為空.");}}11.請求日志和性能日志記錄基于MediatR 管道實現請求日志和性能日志記錄 。

推薦閱讀