当前位置: 首页 > news >正文

MediatR 框架使用FluentValidation对Comand/Query进行自动拦截验证

简介

       

目录

简介

1. MediatR项目框架

2. 实现步骤

步骤 1:编写管道行为

1. query 查询的管道

2. command命令的管道

 步骤 2:注册验证器和管道行为

步骤 3:定义命令类

 步骤 4:定义处理程序

步骤 5:编写命令验证器

 步骤 6:使用方法

3. 总结


        在使用 MediatR 框架时,我们经常需要对命令对象进行验证。为了实现自动验证,我们可以使用 MediatR 的管道行为在命令处理之前执行验证逻辑。本文档将介绍如何在控制器外部使用 MediatR 的管道行为来自动验证实现了 ICommand/IRequest 接口的类,并提供正确地注册验证器和管道行为的方法。

1. MediatR项目框架

 使用Mediator来构建项目框架具有一系列的优点和缺点。以下是对这些优缺点的详细分析:

优点:

  1. 解耦与简化通信:Mediator架构的核心思想是通过一个中介者对象来管理系统中各个组件之间的交互,从而实现了对象之间的解耦。这使得组件之间的通信更加简单,降低了系统的复杂性,提高了代码的可读性和可维护性。
  2. 易于扩展和修改:由于系统的组件之间是通过中介者进行通信的,因此当需要添加或删除组件时,只需要修改中介者的代码,而不需要修改其他组件的代码。这使得系统的扩展和修改变得更加容易。
  3. 集中控制:中介者对象可以集中控制组件之间的交互,确保它们按照预定的规则进行通信。这有助于减少系统中的错误和冲突,提高系统的稳定性和可靠性。

缺点:

  1. 性能开销:由于所有的组件都通过中介者进行通信,这可能会导致一定的性能开销。特别是在处理大量消息或复杂交互时,中介者可能成为性能瓶颈。
  2. 过度依赖中介者:如果系统过度依赖中介者对象,那么中介者的设计和实现可能会变得非常复杂。一旦中介者出现问题,整个系统可能会受到影响。
  3. 不适用于所有场景:虽然Mediator架构在某些场景下非常有用,但它并不适用于所有类型的项目。在某些情况下,使用其他架构可能更为合适。
ProductManage/
│
├── Controllers/            // 控制器文件夹
│   └── ProductController.cs
│
├── Models/                 // 模型文件夹
│   └── Product.cs
│
├── Application/            // 应用层文件夹
│   ├── Commands/           // 命令文件夹
│   │   └── CreateProductCommand.cs
│   │
│   ├── Queries/            // 查询文件夹
│   │   └── GetProductQuery.cs
│   │
│   └── Handlers/           // 处理程序文件夹
│       ├── CreateProductCommandHandler.cs
│       └── GetProductQueryHandler.cs
│
├── Infrastructure/         // 基础设施层文件夹
│   └── Persistence/        // 持久化文件夹
│       └── DbContext.cs
│
├── Domain/                  // 领域层文件夹
│   └── Entities/            // 实体文件夹
│       └── Product.cs
│
├── Validators/              // 验证器文件夹
│   └── CreateProductCommandValidator.cs
│
└── Startup.cs               // 启动文件
2. 实现步骤
步骤 1:编写管道行为

编写一个管道行为来执行验证逻辑,这个管道行为将在命令处理之前执行验证。由于ICommand继承自IRequest接口,所以只需要添加IRequest管道拦截器

using FluentValidation;
using MediatR;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
public class ValidationQueryBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>where TRequest : IRequest<TResponse>
{private readonly IEnumerable<IValidator<TRequest>> _validators;public ValidationQueryBehavior(IEnumerable<IValidator<TRequest>> validators){_validators = validators;}public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next, CancellationToken cancellationToken){// 执行所有验证器var failures = _validators.Select(v => v.Validate(request)).SelectMany(result => result.Errors).Where(error => error != null).ToList();var failuresAsync = _validators.Select(async v => await v.ValidateAsync(request)).SelectMany(result => result.Result.Errors).Where(error => error != null).ToList();failures.AddRange(failuresAsync);if (failures.Any()){throw new DecBussinessExpection(failures.FirstOrDefault().ErrorMessage, Convert.ToInt32(failures.FirstOrDefault().ErrorCode));}// 如果通过验证,则继续执行下一个处理程序return await next();}}

 步骤 2:注册验证器和管道行为

接下来,我们需要将验证器和管道行为注册到 DI 容器中,以便在 MediatR 的管道中使用它们进行自动验证。

 
using FluentValidation.AspNetCore;
using MediatR;
using Microsoft.Extensions.DependencyInjection;
using System.Reflection;public class Startup
{public void ConfigureServices(IServiceCollection services){var assemblies = Directory.GetFiles(AppDomain.CurrentDomain.BaseDirectory, "ProductManage.Application.*.dll", SearchOption.TopDirectoryOnly).Select(Assembly.LoadFrom).ToArray();// 注册 MediatRbuilder.Services.AddMediatR(assemblies);// 注册 FluentValidation 验证器builder.Services.AddValidatorsFromAssemblies(assemblies).AddFluentValidationAutoValidation().AddFluentValidationClientsideAdapters().AddMemoryCache().AddRuleEngine();// 注册管道行为builder.Services.AddTransient(typeof(IPipelineBehavior<,>), typeof(ValidationQueryBehavior<,>));}
}

步骤 3:定义命令类

我们需要定义一个实现了 ICommand 接口的命令类。这个命令类将在 MediatR 管道中被自动验证。

public class CreateProductCommand : ICommand<ProductDTO>
{public string Name { get; set; }public decimal Price { get; set; }
}

 步骤 4:定义处理程序

定义一个实现ICommandHandler接口的处理程序类,该类主要实现业务逻辑。

 public class CreateProductHandler : ICommandHandler<CreateProductCommand, ProductDto>{public Task<ProductDto> Handle(CreateProductCommand request, CancellationToken cancellationToken){//实现业务逻辑}}

步骤 5:编写命令验证器

然后,我们需要编写一个验证器来验证命令类。这个验证器将使用 FluentValidation 等验证库来定义验证规则。

 
using FluentValidation;public class CreateProductCommandValidator : AbstractValidator<CreateProductCommand>
{private IProductService _productService;public CreateProductCommandValidator(IProductService  productService){ _productService=productService;}public override async Task<ValidationResult> ValidateAsync(ValidationContext<CreateProductCommand> context, CancellationToken cancellation = default){RuleFor(it => it.Name).NotNull().CustomException(CustomerErrorMsg.名称不能为空);var command = context.InstanceToValidate;if (await _decCustomerMainService.CheckData()){return new ValidationResult(new[] { new CustomValidationFailure(ProductErrorMsg.该商品不存在) });}return await base.ValidateAsync(context, cancellation);}
}
 步骤 6:使用方法
 [HttpPost()]public async Task<ApiResponse<ProductDTO>> Create(CreateProductReq requestDto){var productInfo= await _mediator.Send(new CreateProductCommand(requestDto));return new ApiResponse<ProductDTO>() { Code = (int)ApiErrorCode.成功, Message = "成功", Result = productInfo};}
3. 总结

       通过以上步骤,我们成功地实现了在控制器外部使用 MediatR 的管道行为来自动验证实现了 ICommand 接口的类。首先,我们定义了命令类和命令验证器。然后,我们注册了验证器和管道行为到 DI 容器中,并编写了管道行为来执行验证逻辑。最终,我们可以在控制器中发送命令,而管道行为会自动执行验证逻辑,并在需要时抛出验证异常。

注:控制器方法参数,FluentValidation会自动拦截验证,不需要额外的在管道里配置拦截验证。

http://www.lryc.cn/news/323498.html

相关文章:

  • TS + Vue3 elementUI 表格列表中如何方便的标识不同类型的内容,颜色区分 enum
  • 从零开始一步一步掌握大语言模型---(2-什么是Token?)
  • 使用专属浏览器在国内直连GPT教程
  • Wireshark 抓包工具与长ping工具pinginfoview使用,安装包
  • 分享Pandas 数据分析实战课程
  • 26. 删除有序数组中的重复项 (Swift版本)
  • python学生作业管理系统flask-django-nodejs-php
  • 蓝桥杯第二天刷真题
  • RK3568 安装jupyter和jupyterlab
  • 简易指南:国内ip切换手机软件怎么弄
  • Git学习笔记之Git 别名
  • 网络安全笔记-day6,NTFS安全权限
  • 云计算系统等保测评对象和指标选取
  • Vue 3项目中结合Element Plus的<el-menu>和CSS3创建锚点,以实现点击菜单项时平滑滚动到对应的锚点目标
  • C语言:数据在内存中的存储
  • DP动态规划入门(数字三角形、破损的楼梯、安全序列)
  • HBase Shell的应用案例
  • Allegro许可管理技巧
  • 34 vue 项目默认暴露出去的 public 文件夹 和 CopyWebpackPlugin
  • Redis 不再“开源”,对中国的影响及应对方案
  • 在CentOS中怎么安装和配置NginxWeb服务器
  • 使用docker搭建Fluentd的教程
  • Python的re模块进行正则表达式操作时的常用方法[回顾学习]
  • Rust之构建命令行程序(五):环境变量
  • ARMday7
  • Ubuntu中安装VSCode的一个指令
  • 生活电子产品拆解分析~汇总目录
  • Tkinter 一文读懂
  • 2核4G服务器阿里云性能测评和优惠价格表
  • Day41:WEB攻防-ASP应用HTTP.SYS短文件文件解析Access注入数据库泄漏