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.mzph.cn/news/764498.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

34 | 到底可不可以使用join?

在实际生产中&#xff0c;关于 join 语句使用的问题&#xff0c;一般会集中在以下两类&#xff1a; 1. 我们 DBA 不让使用 join&#xff0c;使用 join 有什么问题呢&#xff1f; 2. 如果有两个大小不同的表做 join&#xff0c;应该用哪个表做驱动表呢&#xff1f; 今天这篇文…

机器学习流程—迁移学习 模型微调

文章目录 机器学习流程—迁移学习 模型微调迁移学习的思想主要优点常见的微调 fine-tuning案例一 VGG19鲜花分类器案例二 ResNet图像分类案例三 BERT 情感分析总结机器学习流程—迁移学习 模型微调 一旦你踏进了机器学习领域,就等同于踏进了“终身学习”之旅。因为机器学习领…

【算法刷题 | 二叉树 02】3.21 二叉树的层序遍历01(5题:二叉树的层序遍历、层序遍历||、右视图、层平均值,以及N叉树的层序遍历)

文章目录 5.二叉树的层序遍历5.1 102_二叉树的层序遍历5.1.1问题5.1.2解法&#xff1a;队列 5.2 107_二叉树的层序遍历||5.2.1问题5.2.2解法&#xff1a;队列 5.3 199_二叉树的右视图5.3.1问题5.3.2解决&#xff1a;队列 5.4 637_二叉树的层平均值5.4.1问题5.4.2解决&#xff1…

.NET Core 服务实现监控可观测性最佳实践

前言 本次实践主要是介绍 .Net Core 服务通过无侵入的方式接入观测云进行全面的可观测。 环境信息 系统环境&#xff1a;Kubernetes编程语言&#xff1a;.NET Core ≥ 2.1日志框架&#xff1a;Serilog探针类型&#xff1a;ddtrace 接入方案 准备工作 DataKit 部署 DataK…

探索神经网络:从前端开发者的视角看AI技术

在当今数字化时代&#xff0c;人工智能&#xff08;AI&#xff09;技术正在以惊人的速度发展&#xff0c;并在各个领域展现出巨大的潜力和影响力。其中&#xff0c;神经网络作为AI领域的核心技术之一&#xff0c;引起了广泛的关注和研究。作为一名前端开发人员&#xff0c;了解…

css设置文字在图片上面显示(使用Position及引入背景图片(background-image: url(path)))

<div class"container"><img src"image.jpg" alt"背景图片"><div class"h-title">这里是文字</div><div class"config-title">这里是文字2</div> </div>方法一&#xff1a;使用绝…

Nodejs运行vue项目时,报错:Error: error:0308010C:digital envelope routines::unsupported

前端项目使用( npm run dev ) 运行vue项目时&#xff0c;出现错误&#xff1a;Error: error:0308010C:digital envelope routines::unsupported 经过探索&#xff0c;发现问题所在&#xff0c;主要是nodeJs V17版本发布了OpenSSL3.0对算法和秘钥大小增加了更为严格的限制&#…

4核16G服务器租用优惠价格,26.52元1个月,半年149元

阿里云4核16G服务器优惠价格26.52元1个月、79.56元3个月、149.00元半年&#xff0c;配置为阿里云服务器ECS经济型e实例ecs.e-c1m4.xlarge&#xff0c;4核16G、按固定带宽 10Mbs、100GB ESSD Entry系统盘&#xff0c;活动链接 aliyunfuwuqi.com/go/aliyun 活动链接打开如下图&a…

Go语言介绍

Go语言介绍 Go语言&#xff0c;又称Golang&#xff0c;是由Google公司开发的一种静态类型、编译型的开源编程语言。自2009年发布以来&#xff0c;Go语言凭借其简洁的语法、强大的并发处理能力和出色的跨平台性能&#xff0c;迅速在编程界崭露头角&#xff0c;成为众多开发者的…

ZHUTI主提2024夏季系列 —「逐·行」

ZHUTI主提全新发布2024夏季「逐行」系列&#xff0c;聚焦当下人与自然的关系&#xff0c;以衣为载体&#xff0c;秉承东方哲学的艺术理念&#xff0c;将美学艺术与主流时尚设计融合&#xff0c;赋予当代时装表达新方向&#xff0c;共创现代女性之美。 取自然之意境&#xff0c…

list.sort()Collections.sort()深入理解

list.sort()&&Collections.sort() 文章目录 list.sort()&&Collections.sort()背景相关代码代码一代码二 原理举一反三 业务场景考虑 背景 业务中经常用到List的sort()方法&#xff0c;但是对于其中return的-1&#xff0c;0&#xff0c;1理解不到位&#xff0c…

蓝桥杯 2022 省B 李白打酒加强版

这题用递归暴力的方法如下&#xff1a; #include<iostream> #include<bits/stdc.h> using namespace std; int num; int N,M; void dfs(int now,int n,int m) {if(now<0 || n>N ||m>M)return ;if(nN && mM){if(now1)num1;return;}dfs(now-1,n,m1…

微服务day05(下) -- ES文档操作 + RestApi + RestClient操作文档

3.1.新增文档 语法&#xff1a; POST /索引库名/_doc/文档id {"字段1": "值1","字段2": "值2","字段3": {"子属性1": "值3","子属性2": "值4"},// ... } 示例&#xff1a; # 插…

内网使用rustdesk进行远程协助

文章目录 前言一、搭建rustdesk中继服务器二、搭建文件下载服务器三、创建引导脚本四、使用 前言 内网没有互联网环境&#xff0c;没法使用互联网上有中继服务器的远程协助工具&#xff0c;如teamviewer、todesk、向日癸等&#xff1b;在内网进行远程维护可以自己搭建中继服务…

网络基础「HTTP」

&#x1f52d;个人主页&#xff1a; 北 海 &#x1f6dc;所属专栏&#xff1a; Linux学习之旅、神奇的网络世界 &#x1f4bb;操作环境&#xff1a; CentOS 7.6 阿里云远程服务器 文章目录 1.再谈协议1.1.认识URL1.2.Encode 和 Decode 2.HTTP 协议2.1.协议格式2.2.见一见请求2.…

OpenAI GPT商店面临质量与合规问题;黄仁勋预测:十年内AI将实时生成游戏画面

&#x1f989; AI新闻 &#x1f680; OpenAI GPT商店面临质量与合规问题 摘要&#xff1a;OpenAI旗下的GPT商店因存在大量涉嫌侵权内容、助长学术不诚实行为及违规内容等问题而引起关注。其中包括未经授权使用迪士尼、漫威角色生成内容的GPT模型&#xff0c;以及声称能绕过剽…

【Docker】常用命令 docker network inspect

文章目录 什么是docker network inspect命令基本用法实际示例检查名为my_network的网络配置检查多个网络的配置 输出格式常用选项--format&#xff1a;自定义输出格式 总结 在Docker中&#xff0c; docker network inspect命令是用于检查网络配置的主要命令之一。本文将深入探…

HCIP的学习(3)

网络类型及数据链路层协议 网络类型分类 P2P网络----点到点网络类型MA网络-----多点接入网络 BMA----广播型多点接入网络NBMA—非广播型多点接入网络&#xff08;快淘汰了&#xff09; 数据链路层协议 MA网络 以太网协议 特点&#xff1a;需要使用MAC地址对设备进行区分…

Java安全 反序列化(5) CC6链原理分析

Java安全 反序列化(5) CC6链原理分析 CC6学习的目的在于其可以无视jdk版本&#xff0c;这条链子更像CC1-LazyMap和URLDNS链子的缝合版 文章目录 Java安全 反序列化(5) CC6链原理分析前言一.CC6的原理和实现以及易错点我们如何实现调用LazyMap.get()方法一个易错点 二.完整CC6P…

【超全详解】Maven工程配置与常见问题解决指南

Maven工程 目录 Maven工程一、如何检查Maven工程是否配置正确&#xff1f;1、检查路径2、检查基本配置3、其他配置 二、Maven的基本操作基本操作install和package的区别 三、获取别人的Maven工程之后如何修改&#xff1f;四、如何正确写好配置文件&#xff1f;1.寻找配置资源2.…