C#如何实现CQRS模式 MediatR库入门与实践指南

来源:网站主作者:葵司头衔:网络博主
导读:本期聚焦于小伙伴创作的《C#如何实现CQRS模式 MediatR库入门与实践指南》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《C#如何实现CQRS模式 MediatR库入门与实践指南》有用,将其分享出去将是对创作者最好的鼓励。

CQRS全称为Command Query Responsibility Segregation,即命令查询职责分离,是一种将系统的写操作(命令)和读操作(查询)分开处理的架构模式。在传统的CRUD架构中,读写操作通常共用同一套模型和逻辑,当系统复杂度提升时,容易出现逻辑耦合、性能瓶颈等问题。而CQRS模式通过分离读写侧,让两者可以独立优化,比如写侧可以专注于数据一致性和业务逻辑,读侧可以针对查询场景做缓存、数据冗余等优化。MediatR是一个基于中介者模式的轻量级库,能够帮助我们优雅地实现CQRS中的命令和查询的派发与处理,避免组件之间的直接依赖。

C#如何实现CQRS模式 MediatR库入门与实践指南

CQRS模式核心概念

CQRS模式主要包含两个核心部分:

  • 命令(Command):代表系统的写操作,比如创建用户、更新订单状态等,命令通常只返回执行结果,不返回业务数据。
  • 查询(Query):代表系统的读操作,比如获取用户列表、查询订单详情等,查询只返回数据,不会修改系统状态。

两者完全独立,拥有各自的模型、处理逻辑甚至数据存储,这也是CQRS和传统架构最大的区别。

MediatR库基础介绍

MediatR的核心作用是作为中介者,接收请求(命令或查询)并将其派发给对应的处理器,发送方不需要知道处理方的存在,只需要依赖MediatR即可。它主要支持两种请求类型:

  • IRequest<T>:对应查询请求,T是返回结果的类型。
  • IRequest:对应命令请求,没有返回结果或者返回简单的执行状态。

对应的处理器分别是IRequestHandler<TRequest, TResponse>IRequestHandler<TRequest>

环境准备与依赖引入

首先创建一个.NET 6及以上的控制台项目或者Web API项目,然后通过NuGet安装MediatR依赖:

<!-- 项目文件中的PackageReference -->
<PackageReference Include="MediatR" Version="12.2.0" />
<PackageReference Include="MediatR.Extensions.Microsoft.DependencyInjection" Version="11.1.0" />

如果是控制台项目,需要在Program.cs中注册MediatR服务:

using MediatR;
using Microsoft.Extensions.DependencyInjection;

var services = new ServiceCollection();
// 注册MediatR,会自动扫描程序集中的请求处理器
services.AddMediatR(typeof(Program).Assembly);
var provider = services.BuildServiceProvider();
var mediator = provider.GetRequiredService<IMediator>();

实现查询侧功能

首先定义一个查询请求,比如获取用户详情的查询:

using MediatR;

// 查询请求,返回用户详情
public class GetUserByIdQuery : IRequest<UserDto>
{
    public int UserId { get; set; }
}

// 用户数据传输对象
public class UserDto
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Email { get; set; }
}

然后实现对应的查询处理器:

using MediatR;

public class GetUserByIdQueryHandler : IRequestHandler<GetUserByIdQuery, UserDto>
{
    // 模拟用户数据存储
    private readonly List<UserDto> _users = new()
    {
        new UserDto { Id = 1, Name = "张三", Email = "zhangsan@ipipp.com" },
        new UserDto { Id = 2, Name = "李四", Email = "lisi@ipipp.com" }
    };

    public Task<UserDto> Handle(GetUserByIdQuery request, CancellationToken cancellationToken)
    {
        var user = _users.FirstOrDefault(u => u.Id == request.UserId);
        return Task.FromResult(user);
    }
}

调用查询的代码如下:

// 发送查询请求
var query = new GetUserByIdQuery { UserId = 1 };
var user = await mediator.Send(query);
Console.WriteLine($"用户ID:{user?.Id},姓名:{user?.Name}");

实现命令侧功能

接下来定义创建用户的命令:

using MediatR;

// 命令请求,无返回结果
public class CreateUserCommand : IRequest
{
    public string Name { get; set; }
    public string Email { get; set; }
}

实现命令处理器:

using MediatR;

public class CreateUserCommandHandler : IRequestHandler<CreateUserCommand>
{
    // 模拟用户存储
    private readonly List<UserDto> _users = new();

    public Task Handle(CreateUserCommand request, CancellationToken cancellationToken)
    {
        var newUser = new UserDto
        {
            Id = _users.Count + 1,
            Name = request.Name,
            Email = request.Email
        };
        _users.Add(newUser);
        Console.WriteLine($"用户{request.Name}创建成功,ID:{newUser.Id}");
        return Task.CompletedTask;
    }
}

调用命令的代码如下:

// 发送命令请求
var command = new CreateUserCommand { Name = "王五", Email = "wangwu@ipipp.com" };
await mediator.Send(command);

进阶实践:命令与查询的验证

实际开发中,我们通常需要在命令或查询执行前做参数验证,MediatR支持通过管道行为(Pipeline Behavior)实现通用逻辑。比如实现一个验证行为:

using MediatR;
using System.ComponentModel.DataAnnotations;

// 通用验证行为
public class ValidationBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
    where TRequest : IRequest<TResponse>
{
    public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next, CancellationToken cancellationToken)
    {
        // 使用DataAnnotations做参数验证
        var validationContext = new ValidationContext(request);
        var validationResults = new List<ValidationResult>();
        if (!Validator.TryValidateObject(request, validationContext, validationResults, true))
        {
            throw new ArgumentException(string.Join(",", validationResults.Select(r => r.ErrorMessage)));
        }
        return await next();
    }
}

然后在命令和查询的属性上添加验证特性:

using System.ComponentModel.DataAnnotations;
using MediatR;

public class CreateUserCommand : IRequest
{
    [Required(ErrorMessage = "用户名不能为空")]
    public string Name { get; set; }

    [Required(ErrorMessage = "邮箱不能为空")]
    [EmailAddress(ErrorMessage = "邮箱格式不正确")]
    public string Email { get; set; }
}

最后注册验证行为:

services.AddTransient(typeof(IPipelineBehavior<,>), typeof(ValidationBehavior<,>));

注意事项

  • 不是所有项目都适合使用CQRS,简单的CRUD项目使用CQRS会增加不必要的复杂度,建议在系统复杂度较高、读写场景差异大的场景下使用。
  • MediatR是中介者模式的实现,不要过度使用,避免所有逻辑都通过MediatR派发,导致请求链路过长,不利于调试。
  • 如果读写侧使用不同的数据库,需要考虑数据同步的问题,通常可以通过事件驱动的方式实现写侧数据变更后同步到读侧存储。

CQRSMediatRC#命令查询分离领域驱动设计修改时间:2026-07-13 02:03:33

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。