新闻中心

.NET中的CQRS和MediatR模式:构建清晰、可维护的应用架构

2025-12-02
浏览次数:
返回列表
CQRS 将读写操作分离,Commands 负责修改状态,Queries 仅获取数据,结合 MediatR 实现松耦合消息处理,通过定义独立的 Command/Query 消息与 Handler,控制器依赖 IMediator 发送请求,提升代码可维护性与扩展性,适用于业务复杂的中大型项目。

.net中的cqrs和mediatr模式:构建清晰、可维护的应用架构

在现代 .NET 应用开发中,随着业务逻辑日益复杂,如何保持代码的清晰性和可维护性成为关键挑战。CQRS(Command Query Responsibility Segregation)与 MediatR 模式结合使用,提供了一种解耦请求处理流程、提升系统可读性与扩展性的有效方案。这种架构方式将“读取数据”和“修改数据”的操作彻底分离,配合中介者模式实现关注点分离。

什么是 CQRS?

CQRS 的核心思想是将应用程序的读操作(Queries)与写操作(Commands)分开处理:

  • Commands(命令):用于修改状态的操作,例如创建订单、更新用户信息。这类操作应返回 void 或结果状态,不应直接返回数据。
  • Queries(查询):仅用于获取数据,不产生副作用,例如列出所有用户、查找某个订单详情。

通过这种分离,可以为读写两端设计不同的模型、数据库甚至技术栈。比如写模型使用事务性强的关系库,读模型使用优化过的视图或 NoSQL 存储。

MediatR 如何协助实现 CQRS?

MediatR 是一个轻量级的 .NET 库,实现了中介者(Mediator)模式,允许你以松耦合的方式发送和处理请求。它非常适合配合 CQRS 使用:

  • 每个 Command 或 Query 被定义为一个独立的消息对象。
  • 对应的 Handler 负责处理该消息,实现具体逻辑。
  • 控制器或其他入口只需依赖 IMediator 接口调用 SendSendAsync,无需知道内部如何处理。

这种方式显著降低了模块间的依赖,提升了测试性和可维护性。

实际应用示例

以下是一个简单的用户注册场景实现:

定义 Command:

微信源码微趣能Weiqn 微信源码微趣能Weiqn

产品介绍微趣能 Weiqn 开源免费的微信公共账号接口系统。MVC框架框架结构清晰、易维护、模块化、扩展性好,性能稳定强大核心-梦有多大核心就有多大,轻松应对各种场景!微趣能系统 以关键字应答为中心 与内容素材库 文本 如图片 语音 视频和应用各类信息整体汇集并且与第三方应用完美结合,强大的前后台管理;人性化的界面设计。开放API接口-灵活多动的API,万名开发者召集中。Weiqn 系统开发者AP

微信源码微趣能Weiqn 1 查看详情 微信源码微趣能Weiqn
public class CreateUserCommand : IRequest<Guid>
{
    public string Name { get; set; }
    public string Email { get; set; }
}

public class CreateUserCommandHandler : IRequestHandler<CreateUserCommand, Guid>
{
    private readonly AppDbContext _context;

    public CreateUserCommandHandler(AppDbContext context)
    {
        _context = context;
    }

    public async Task<Guid> Handle(CreateUserCommand request, CancellationToken ct)
    {
        var user = new User(request.Name, request.Email);
        await _context.Users.AddAsync(user, ct);
        await _context.S*eChangesAsync(ct);
        return user.Id;
    }
}

定义 Query:

public class GetUserByIdQuery : IRequest<UserDto>
{
    public Guid Id { get; set; }
}

public class GetUserByIdQueryHandler : IRequestHandler<GetUserByIdQuery, UserDto>
{
    private readonly AppDbContext _context;

    public GetUserByIdQueryHandler(AppDbContext context)
    {
        _context = context;
    }

    public async Task<UserDto> Handle(GetUserByIdQuery request, CancellationToken ct)
    {
        return await _context.Users
            .Where(u => u.Id == request.Id)
            .Select(u => new UserDto(u.Id, u.Name, u.Email))
            .FirstOrDefaultAsync(ct);
    }
}

在控制器中使用:

[ApiController]
[Route("[controller]")]
public class UsersController : ControllerBase
{
    private readonly IMediator _mediator;

    public UsersController(IMediator mediator)
    {
        _mediator = mediator;
    }

    [HttpPost]
    public async Task<ActionResult<Guid>> Create([FromBody] CreateUserCommand command)
    {
        var id = await _mediator.Send(command);
        return CreatedAtAction(nameof(Get), new { id }, id);
    }

    [HttpGet("{id:guid}")]
    public async Task<ActionResult<UserDto>> Get(Guid id)
    {
        var query = new GetUserByIdQuery { Id = id };
        var user = await _mediator.Send(query);
        if (user == null) return NotFound();
        return Ok(user);
    }
}

整个流程清晰明了,职责分明,新增功能只需添加新的消息和处理器,不影响现有代码。

优势与适用场景

采用 CQRS + MediatR 架构的主要好处包括:

  • 逻辑分层清晰,易于理解与维护。
  • 便于实施横切关注点(如日志、验证、事务),可通过行为管道(Pipeline Beh*iors)统一处理。
  • 支持未来演进,比如引入事件溯源、缓存读模型、分布式处理等。

适合中大型项目或预期会持续增长的系统。对于简单 CRUD 应用,可能引入额外复杂度,需权衡使用。

基本上就这些。合理运用 CQRS 与 MediatR,能让 .NET 项目的结构更整洁,团队协作更顺畅。

以上就是.NET中的CQRS和MediatR模式:构建清晰、可维护的应用架构的详细内容,更多请关注其它相关文章!


# cqrs  # 处理器  # mediatr  # 天台台州网站建设  # 小麦种子网站建设  # seo网络营销课程  # 网站推广与网站优化实验  # 上饶哪家网站推广好用啊  # seo优化技巧和好处  # 烤乳猪营销推广方案设计  # 苏州抖音营销推广哪靠谱  # SEO监控宠物猫  # 南通网站建设官网推荐  # 相关文章  # 适用于  # 就有  # 文档  # 如何实现  # 何为  # 注册表  # 只需  # 是一个  # .net  # 用户注册  # 应用开发  # ai  #   # app 


相关栏目: 【 科技资讯46185 】 【 网络学院92790


相关推荐: Python类型检查:优化关联可选属性的Mypy推断策略  J*aScript:在map操作中高效处理空数组  2306选座时如何选靠窗位置_12306选座靠窗座位查看方法解析  CSS布局:解决全屏元素100%尺寸与外边距导致的页面溢出问题  XML中包含HTML标签导致解析错误? 正确嵌入非XML数据的两种方法  在Blazor WebAssembly应用中动态注入客户端特定指标代码的策略  初次安装JDK时环境变量如何正确配置_J*A_HOME与PATH设置规则讲解  Golang如何处理RPC请求负载均衡_Golang RPC请求负载均衡策略与实践  J*aScript异步迭代器_j*ascript异步遍历  Excel中VLOOKUP的第四个参数是干什么用的_Excel VLOOKUP第四参数作用解析  AO3最新官网入口公告_2025AO3镜像站实时查询方法  必由学在线入口 必由学网页版快速登录入口  写好的html代码怎么运行出来_运行写好的html代码方法【教程】  期待已久:小米17 Ultra、小米首款NAS本月登场  LINQ to XML为何解析失败? 深入理解C# XDocument的异常处理  jQuery Mask 插件中实现电话号码固定前导零的教程  uc浏览器网页版入口 uc浏览器网页版最新网址  Win10怎么设置静态IP地址 Win10手动配置IP地址步骤【指南】  CSS响应式网页如何实现主次模块比例自适应_flex-grow与flex-shrink调整  Windows10怎么开启存储感知 Windows10系统设置自动清理临时文件释放C盘空间【教程】  sublime怎么格式化代码_sublime代码美化与一键排版插件配置  Spring Boot内嵌服务器与J*a EE全栈特性:选择与部署策略  steam官方网页快速访问 steam账号注册全流程  哔哩哔哩忘记密码了怎么找回_哔哩哔哩密码找回方法  在J*a中如何开发简易仓库管理与库存统计_仓库管理库存统计项目实战解析  如何在Promise链中优雅地中断后续then执行  Win11怎么设置鼠标指针速度_Win11提高鼠标指针精确度选项  《主播少女的秘密账号迷宫》首支宣传片  win11专注助手在哪 Win11免打扰模式设置与自动化规则【指南】  押井守高度称赞《辐射4》:玩了八年都停不下来!  魅族20怎样在浏览器开无图省流_iPhone魅族20浏览器开无图省流【流量节省】  如何设置Windows Defender的定时扫描_计划任务实现自动杀毒【安全】  EMS快递官网app_中国邮政速递物流手机客户端  深入理解J*a链表中的IPosition接口与使用  outlook中文官网入口地址 outlook官方中文版直达首页链接  电脑屏幕颜色不舒服怎么办_Windows夜间模式与色彩校准教程【护眼技巧】  c++如何使用std::memory_order控制原子操作顺序_c++ C++11内存模型详解  J*a里如何实现订单支付与库存同步功能_支付库存同步项目开发方法说明  神庙逃亡小游戏在线玩 神庙逃亡小游戏入口  迅雷下载到U盘速度很慢怎么办_迅雷U盘下载慢优化方法  uc手机浏览器网页版入口 uc浏览器手机版便捷登录首页  在React函数组件中利用原生HTML5进行邮箱地址验证  学习通在线学习平台 学习通网页版直接进入课程中心  微信网页版官方快速登录入口 微信网页版网页版账号直达  抖音创作助手登录入口_抖音创作辅助工具官网直达  夸克浏览器图书入口 夸克手机浏览器阅读入口  优化HTML表单样式:解决输入框焦点跳动与元素间距问题  Fabric模组开发:自定义物品与物品组的现代管理方法  单12V-2&#215;6实现为RTX 5090供电750W!甚至都没敢跑分  解决Flask中Quill编辑器内容提交失败及TypeError的指南 

搜索