当前位置: 首页 > 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会自动拦截验证,不需要额外的在管道里配置拦截验证。

相关文章:

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

简介 目录 简介 1. MediatR项目框架 2. 实现步骤 步骤 1&#xff1a;编写管道行为 1. query 查询的管道 2. command命令的管道 步骤 2&#xff1a;注册验证器和管道行为 步骤 3&#xff1a;定义命令类 步骤 4&#xff1a;定义处理程序 步骤 5&#xff1a;编写命令验证器…...

TS + Vue3 elementUI 表格列表中如何方便的标识不同类型的内容,颜色区分 enum

TS Vue3 elementUI 表格列表中如何方便的标识不同类型的内容&#xff0c;颜色区分 enum 本文内容为 TypeScript 一、基础知识 在展示列表的时候&#xff0c;列表中的某个数据可能是一个类别&#xff0c;比如&#xff1a; enum EnumOrderStatus{"未受理" 1,"…...

从零开始一步一步掌握大语言模型---(2-什么是Token?)

了解自然语言处理或者听说过大语言模型的同学都听过&#xff0c;token。一般来说&#xff0c;它代表的是语言中不可再分的最小单元。我们人类的语言不仅有文字&#xff0c;还有语音。针对文字、语音来说&#xff0c;它们都各自有不同的划分token的方法。本节将尽可能详细的介绍…...

使用专属浏览器在国内直连GPT教程

Wildcard官方推特发文说他们最近推出了一款专门为访问OpenAI设计的浏览器。 根据官方消息&#xff0c;这是一款专门为访问OpenAI优选网络设计的浏览器&#xff0c;它通过为用户提供专用的家庭网络出口&#xff0c;确保了快速、稳定的连接。 用这个浏览器的最大好处就是直接用浏…...

Wireshark 抓包工具与长ping工具pinginfoview使用,安装包

一、Wireshark使用 打开软件&#xff0c;选择以太网 1、时间设置时间显示格式 这个时间戳不易直观&#xff0c;我们修改 2、抓包使用的命令 1&#xff09;IP地址过滤 ip.addr192.168.1.114 //筛选出源IP或者目的IP地址是192.168.1.114的全部数据包。 ip.sr…...

分享Pandas 数据分析实战课程

分享Pandas 数据分析实战课程&#xff0c;3 小时掌握数据分析核心技能。 链接&#xff1a;https://pan.baidu.com/s/1Ikk3I1dfoFO0id3EBZJdGg?pwd4y83 提取码&#xff1a;4y83 链接&#xff1a;https://pan.quark.cn/s/fa2acd7513f4 提取码&#xff1a;yWu7...

26. 删除有序数组中的重复项 (Swift版本)

题目描述 给你一个 非严格递增排列 的数组 nums &#xff0c;请你删除重复出现的元素&#xff0c;使每个元素只出现一次 &#xff0c;返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回 nums 中唯一元素的个数。 考虑 nums 的唯一元素的数量为 k &#xff0…...

python学生作业管理系统flask-django-nodejs-php

课题主要分为三大模块&#xff1a;即管理员模块和学生、教师模块&#xff0c;主要功能包括&#xff1a;学生、教师、作业信息、学习模块、教学评价、学习情况等&#xff1b; 关键词&#xff1a;学生作业管理系统&#xff1b;作业信息 目录 摘 要 I Abstrac II 目录 III 1绪论 1…...

蓝桥杯第二天刷真题

public class Main {public static void main(String [] args) { //存大数方法String s"202320232023"; // 定义一个字符串&#xff0c;它将被转换为结束循环的数值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切换手机软件怎么弄

在网络访问受到地域限制的情况下&#xff0c;使用国内IP切换手机软件可以帮助用户轻松访问被屏蔽的内容&#xff0c;扩展网络体验。以下是虎观代理小二分享的使用国内IP切换手机软件的简易指南。并提供一些注意事项。 如何在手机上使用国内IP切换软件 步骤一&#xff1a;选择I…...

Git学习笔记之Git 别名

Git 并不会在你输入部分命令时自动推断出你想要的命令。 如果不想每次都输入完整的 Git 命令&#xff0c;可以通过 git config 文件来轻松地为每一个命令设置一个别名。命令&#xff1a; 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 云计算应用场景说明。简要理解下图&#xff0c;主要是云计算系统安全保护责任分担原则和云服务模式适用性原则&#xff0c;指导后续的测评对象和指标选取。 2、测评对象选择 测评对象 IaaS模式 PaaS模式…...

Vue 3项目中结合Element Plus的<el-menu>和CSS3创建锚点,以实现点击菜单项时平滑滚动到对应的锚点目标

安装Element Plus&#xff1a; 确保已经安装了Element Plus库。可以使用npm或者yarn进行安装&#xff0c;具体步骤与上文提到的相同。 引入Element Plus&#xff1a; 在你的Vue 3项目中引入所需的Element Plus组件和样式。 创建el-menu&#xff1a; 在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动态规划入门(数字三角形、破损的楼梯、安全序列)

一、动态规划&#xff08;DP&#xff09;简介 动态规划&#xff08;Dynamic Programming&#xff0c;简称DP&#xff09;是运筹学的一个分支&#xff0c;它是一种通过将复杂问题分解成多个重叠的子问题&#xff0c;并通过子问题的解来构建整个问题的解的算法。在动态规划中&am…...

HBase Shell的应用案例

电商( eshop)平台具有海量数据、高并发访问、高速读写等特征&#xff0c;适合使用HBase分布式数据库进行数据存储。本节通过一个 HBase在电商平台的应用案例&#xff0c;熟练掌握并综合运用HBase Shell命令行终端提供的各种操作命令。 一、电商(eshop)平台的逻辑数据模型 在H…...

Allegro许可管理技巧

在数字化时代&#xff0c;软件许可管理对于企业的运营至关重要。然而&#xff0c;许多企业在实施软件管理过程中会遇到各种问题。Allegro许可管理作为一款高效、合规的管理工具&#xff0c;能够帮助企业解决常见的许可管理问题。本文将深入探讨Allegro许可管理中的实用技巧&…...

34 vue 项目默认暴露出去的 public 文件夹 和 CopyWebpackPlugin

前言 这里说一下 vue.config.js 中的一些 public 文件夹是怎么暴露出去的? 我们常见的 CopyWebpackPlugin 是怎么工作的 ? 这个 也是需要 一点一点积累的, 因为 各种插件 有很多, 不过 我们仅仅需要 明白常见的这些事干什么的即可 当然 以下内容会涉及到一部分vue-cli,…...

C++_核心编程_多态案例二-制作饮品

#include <iostream> #include <string> using namespace std;/*制作饮品的大致流程为&#xff1a;煮水 - 冲泡 - 倒入杯中 - 加入辅料 利用多态技术实现本案例&#xff0c;提供抽象制作饮品基类&#xff0c;提供子类制作咖啡和茶叶*//*基类*/ class AbstractDr…...

树莓派超全系列教程文档--(61)树莓派摄像头高级使用方法

树莓派摄像头高级使用方法 配置通过调谐文件来调整相机行为 使用多个摄像头安装 libcam 和 rpicam-apps依赖关系开发包 文章来源&#xff1a; http://raspberry.dns8844.cn/documentation 原文网址 配置 大多数用例自动工作&#xff0c;无需更改相机配置。但是&#xff0c;一…...

Xshell远程连接Kali(默认 | 私钥)Note版

前言:xshell远程连接&#xff0c;私钥连接和常规默认连接 任务一 开启ssh服务 service ssh status //查看ssh服务状态 service ssh start //开启ssh服务 update-rc.d ssh enable //开启自启动ssh服务 任务二 修改配置文件 vi /etc/ssh/ssh_config //第一…...

LeetCode - 394. 字符串解码

题目 394. 字符串解码 - 力扣&#xff08;LeetCode&#xff09; 思路 使用两个栈&#xff1a;一个存储重复次数&#xff0c;一个存储字符串 遍历输入字符串&#xff1a; 数字处理&#xff1a;遇到数字时&#xff0c;累积计算重复次数左括号处理&#xff1a;保存当前状态&a…...

测试markdown--肇兴

day1&#xff1a; 1、去程&#xff1a;7:04 --11:32高铁 高铁右转上售票大厅2楼&#xff0c;穿过候车厅下一楼&#xff0c;上大巴车 &#xffe5;10/人 **2、到达&#xff1a;**12点多到达寨子&#xff0c;买门票&#xff0c;美团/抖音&#xff1a;&#xffe5;78人 3、中饭&a…...

Java多线程实现之Callable接口深度解析

Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...

Python爬虫(一):爬虫伪装

一、网站防爬机制概述 在当今互联网环境中&#xff0c;具有一定规模或盈利性质的网站几乎都实施了各种防爬措施。这些措施主要分为两大类&#xff1a; 身份验证机制&#xff1a;直接将未经授权的爬虫阻挡在外反爬技术体系&#xff1a;通过各种技术手段增加爬虫获取数据的难度…...

什么?连接服务器也能可视化显示界面?:基于X11 Forwarding + CentOS + MobaXterm实战指南

文章目录 什么是X11?环境准备实战步骤1️⃣ 服务器端配置(CentOS)2️⃣ 客户端配置(MobaXterm)3️⃣ 验证X11 Forwarding4️⃣ 运行自定义GUI程序(Python示例)5️⃣ 成功效果![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/55aefaea8a9f477e86d065227851fe3d.pn…...

USB Over IP专用硬件的5个特点

USB over IP技术通过将USB协议数据封装在标准TCP/IP网络数据包中&#xff0c;从根本上改变了USB连接。这允许客户端通过局域网或广域网远程访问和控制物理连接到服务器的USB设备&#xff08;如专用硬件设备&#xff09;&#xff0c;从而消除了直接物理连接的需要。USB over IP的…...

云原生玩法三问:构建自定义开发环境

云原生玩法三问&#xff1a;构建自定义开发环境 引言 临时运维一个古董项目&#xff0c;无文档&#xff0c;无环境&#xff0c;无交接人&#xff0c;俗称三无。 运行设备的环境老&#xff0c;本地环境版本高&#xff0c;ssh不过去。正好最近对 腾讯出品的云原生 cnb 感兴趣&…...