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来构建项目框架具有一系列的优点和缺点。以下是对这些优缺点的详细分析:
优点:
- 解耦与简化通信:Mediator架构的核心思想是通过一个中介者对象来管理系统中各个组件之间的交互,从而实现了对象之间的解耦。这使得组件之间的通信更加简单,降低了系统的复杂性,提高了代码的可读性和可维护性。
- 易于扩展和修改:由于系统的组件之间是通过中介者进行通信的,因此当需要添加或删除组件时,只需要修改中介者的代码,而不需要修改其他组件的代码。这使得系统的扩展和修改变得更加容易。
- 集中控制:中介者对象可以集中控制组件之间的交互,确保它们按照预定的规则进行通信。这有助于减少系统中的错误和冲突,提高系统的稳定性和可靠性。
缺点:
- 性能开销:由于所有的组件都通过中介者进行通信,这可能会导致一定的性能开销。特别是在处理大量消息或复杂交互时,中介者可能成为性能瓶颈。
- 过度依赖中介者:如果系统过度依赖中介者对象,那么中介者的设计和实现可能会变得非常复杂。一旦中介者出现问题,整个系统可能会受到影响。
- 不适用于所有场景:虽然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会自动拦截验证,不需要额外的在管道里配置拦截验证。
相关文章:
MediatR 框架使用FluentValidation对Comand/Query进行自动拦截验证
简介 目录 简介 1. MediatR项目框架 2. 实现步骤 步骤 1:编写管道行为 1. query 查询的管道 2. command命令的管道 步骤 2:注册验证器和管道行为 步骤 3:定义命令类 步骤 4:定义处理程序 步骤 5:编写命令验证器…...
TS + Vue3 elementUI 表格列表中如何方便的标识不同类型的内容,颜色区分 enum
TS Vue3 elementUI 表格列表中如何方便的标识不同类型的内容,颜色区分 enum 本文内容为 TypeScript 一、基础知识 在展示列表的时候,列表中的某个数据可能是一个类别,比如: enum EnumOrderStatus{"未受理" 1,"…...
从零开始一步一步掌握大语言模型---(2-什么是Token?)
了解自然语言处理或者听说过大语言模型的同学都听过,token。一般来说,它代表的是语言中不可再分的最小单元。我们人类的语言不仅有文字,还有语音。针对文字、语音来说,它们都各自有不同的划分token的方法。本节将尽可能详细的介绍…...
使用专属浏览器在国内直连GPT教程
Wildcard官方推特发文说他们最近推出了一款专门为访问OpenAI设计的浏览器。 根据官方消息,这是一款专门为访问OpenAI优选网络设计的浏览器,它通过为用户提供专用的家庭网络出口,确保了快速、稳定的连接。 用这个浏览器的最大好处就是直接用浏…...
Wireshark 抓包工具与长ping工具pinginfoview使用,安装包
一、Wireshark使用 打开软件,选择以太网 1、时间设置时间显示格式 这个时间戳不易直观,我们修改 2、抓包使用的命令 1)IP地址过滤 ip.addr192.168.1.114 //筛选出源IP或者目的IP地址是192.168.1.114的全部数据包。 ip.sr…...
分享Pandas 数据分析实战课程
分享Pandas 数据分析实战课程,3 小时掌握数据分析核心技能。 链接:https://pan.baidu.com/s/1Ikk3I1dfoFO0id3EBZJdGg?pwd4y83 提取码:4y83 链接:https://pan.quark.cn/s/fa2acd7513f4 提取码:yWu7...
26. 删除有序数组中的重复项 (Swift版本)
题目描述 给你一个 非严格递增排列 的数组 nums ,请你删除重复出现的元素,使每个元素只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回 nums 中唯一元素的个数。 考虑 nums 的唯一元素的数量为 k ࿰…...
python学生作业管理系统flask-django-nodejs-php
课题主要分为三大模块:即管理员模块和学生、教师模块,主要功能包括:学生、教师、作业信息、学习模块、教学评价、学习情况等; 关键词:学生作业管理系统;作业信息 目录 摘 要 I Abstrac II 目录 III 1绪论 1…...
蓝桥杯第二天刷真题
public class Main {public static void main(String [] args) { //存大数方法String s"202320232023"; // 定义一个字符串,它将被转换为结束循环的数值long end Long.parseLong(s);long sum 0;long primarynumber 1;for(int i 1; i<end; i) {long …...
RK3568 安装jupyter和jupyterlab
首先需要RK3568运行Ubuntu,之前的文章有关于如何安装Ubuntu以及遇到的问题 其次需要安装Miniconda3,详细安装教程:RK3568 安装Miniconda3-CSDN博客 准备好这两步之后就可以开始: 1、更新软件源和软件 sudo apt update sudo apt upgrade sudo apt-get dist-upgrade 2、…...
简易指南:国内ip切换手机软件怎么弄
在网络访问受到地域限制的情况下,使用国内IP切换手机软件可以帮助用户轻松访问被屏蔽的内容,扩展网络体验。以下是虎观代理小二分享的使用国内IP切换手机软件的简易指南。并提供一些注意事项。 如何在手机上使用国内IP切换软件 步骤一:选择I…...
Git学习笔记之Git 别名
Git 并不会在你输入部分命令时自动推断出你想要的命令。 如果不想每次都输入完整的 Git 命令,可以通过 git config 文件来轻松地为每一个命令设置一个别名。命令: git config --global alias.别名 命令例如 git config --global alias.co checkout git …...
网络安全笔记-day6,NTFS安全权限
文章目录 NTFS安全权限常用文件系统文件安全权限打开文件安全属性修改文件安全权限1.取消父项继承权限2.添加用户访问权限3.修改用户权限4.验证文件权限5.总结权限 强制继承父项权限文件复制移动权限影响跨分区同分区 总结1.权限累加2.管理员最高权限2.管理员最高权限 NTFS安全…...
云计算系统等保测评对象和指标选取
1、云计算服务模式与控制范围关系 参考GBT22239-2019《基本要求》附录D 云计算应用场景说明。简要理解下图,主要是云计算系统安全保护责任分担原则和云服务模式适用性原则,指导后续的测评对象和指标选取。 2、测评对象选择 测评对象 IaaS模式 PaaS模式…...
Vue 3项目中结合Element Plus的<el-menu>和CSS3创建锚点,以实现点击菜单项时平滑滚动到对应的锚点目标
安装Element Plus: 确保已经安装了Element Plus库。可以使用npm或者yarn进行安装,具体步骤与上文提到的相同。 引入Element Plus: 在你的Vue 3项目中引入所需的Element Plus组件和样式。 创建el-menu: 在Vue组件中使用<el-me…...
C语言:数据在内存中的存储
目录 一、 整数在内存中的存储二、 大小端字节序和字节序判断1.什么是大小端2.为什么有大小端3.练习(1)练习1(2)练习2(3)练习3(4)练习4(5)练习5(6)练习6 三、 浮点数在内存中的存储1.练习2.浮点数的存储(1) 浮点数存的过程(2)浮点数取的过程 3.题目解析 一、 整数在内存中的存储…...
DP动态规划入门(数字三角形、破损的楼梯、安全序列)
一、动态规划(DP)简介 动态规划(Dynamic Programming,简称DP)是运筹学的一个分支,它是一种通过将复杂问题分解成多个重叠的子问题,并通过子问题的解来构建整个问题的解的算法。在动态规划中&am…...
HBase Shell的应用案例
电商( eshop)平台具有海量数据、高并发访问、高速读写等特征,适合使用HBase分布式数据库进行数据存储。本节通过一个 HBase在电商平台的应用案例,熟练掌握并综合运用HBase Shell命令行终端提供的各种操作命令。 一、电商(eshop)平台的逻辑数据模型 在H…...
Allegro许可管理技巧
在数字化时代,软件许可管理对于企业的运营至关重要。然而,许多企业在实施软件管理过程中会遇到各种问题。Allegro许可管理作为一款高效、合规的管理工具,能够帮助企业解决常见的许可管理问题。本文将深入探讨Allegro许可管理中的实用技巧&…...
34 vue 项目默认暴露出去的 public 文件夹 和 CopyWebpackPlugin
前言 这里说一下 vue.config.js 中的一些 public 文件夹是怎么暴露出去的? 我们常见的 CopyWebpackPlugin 是怎么工作的 ? 这个 也是需要 一点一点积累的, 因为 各种插件 有很多, 不过 我们仅仅需要 明白常见的这些事干什么的即可 当然 以下内容会涉及到一部分vue-cli,…...
论文降AI工具测评:10款对比后这款低至0.12%通过率极高
2026年国内学术圈AIGC检测规则全面更新,学生和科研人员对论文降AI工具的需求持续攀升,一季度用户规模已突破2000万。但市面上各类工具的技术能力差异极大,多数还停留在同义词替换、简单调整句式的浅层改写阶段,根本无法应对知网、…...
在超大数据集下 DuckDB 与 MySQL 查询速度对比吨
一、什么是urllib3? urllib3 是一个用于处理 HTTP 请求和连接池的强大、用户友好的 Python 库。 它可以帮助你: 发送各种 HTTP 请求(GET, POST, PUT, DELETE等)。 管理连接池,提高网络请求效率。 处理重试和重定向。 支…...
HWA_19leetcode83删除链表中的重复元素
题目题解 class Solution:def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]:#从链表的头节点开始访问每一个节点cur head#在访问过程中,只要当前节点和当前节点的下一个节点有值,就不断地访问下去while cur and cur.nex…...
Flyback电路关键元件选型与设计实战(1)
1. 反激式电源保护元件的重要性 反激式开关电源(Flyback Converter)作为最常见的隔离型电源拓扑之一,其可靠性很大程度上取决于保护电路的设计。在实际项目中,我见过太多因为保护元件选型不当导致的炸机事故——从保险丝误熔断到压…...
MiniMax 闫俊杰向左, DeepSeek 梁文锋向右
2026 年初,大模型赛道有两件事值得关注。3 月,MiniMax 发布首份年报,营收爆发式增长。2 月,DeepSeek 创始人梁文锋接受 Lex Fridman 4 小时访谈,震惊全球 AI 圈。两个年轻人,两种打法,两条完全不…...
x64dbg实战指南:从零开始掌握程序调试与分析技巧
1. x64dbg调试器入门:为什么选择它? 第一次接触逆向工程的朋友,往往会被各种调试工具搞得眼花缭乱。我刚开始学习时也试过OllyDbg、WinDbg这些老牌工具,但最终发现x64dbg才是最适合新手的"瑞士军刀"。它最大的优势就是同…...
SteamCleaner游戏空间清理完整指南:快速释放硬盘空间的终极解决方案
SteamCleaner游戏空间清理完整指南:快速释放硬盘空间的终极解决方案 【免费下载链接】SteamCleaner :us: A PC utility for restoring disk space from various game clients like Origin, Steam, Uplay, Battle.net, GoG and Nexon :us: 项目地址: https://gitco…...
从电子琴到智能家居:无源蜂鸣器如何玩出花样?附ESP32播放《超级玛丽》主题曲代码
无源蜂鸣器的创意交响曲:从电子琴到游戏音效的ESP32实战指南 在创客和物联网开发的世界里,声音交互常常是项目中最容易被忽视却又最能提升用户体验的环节。无源蜂鸣器这个看似简单的元件,实际上蕴藏着惊人的创意潜力——它不只是发出单调的&q…...
【Maxwell16.0】实战解析:电机三维空载仿真中的常见问题与解决方案
1. Maxwell16.0电机三维空载仿真入门指南 第一次打开Maxwell16.0做电机三维仿真时,很多人都会被复杂的界面吓到。其实只要掌握几个关键步骤,就能快速上手。我刚开始学习时也走了不少弯路,现在把最实用的操作方法分享给大家。 三维空载仿真的核…...
