新闻中心
.NET中的CQRS和MediatR模式:构建清晰、可维护的应用架构
CQRS 将读写操作分离,Commands 负责修改状态,Queries 仅获取数据,结合 MediatR 实现松耦合消息处理,通过定义独立的 Command/Query 消息与 Handler,控制器依赖 IMediator 发送请求,提升代码可维护性与扩展性,适用于业务复杂的中大型项目。

在现代 .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 接口调用 Send 或 SendAsync,无需知道内部如何处理。
这种方式显著降低了模块间的依赖,提升了测试性和可维护性。
实际应用示例
以下是一个简单的用户注册场景实现:
定义 Command:
微信源码微趣能Weiqn
产品介绍微趣能 Weiqn 开源免费的微信公共账号接口系统。MVC框架框架结构清晰、易维护、模块化、扩展性好,性能稳定强大核心-梦有多大核心就有多大,轻松应对各种场景!微趣能系统 以关键字应答为中心 与内容素材库 文本 如图片 语音 视频和应用各类信息整体汇集并且与第三方应用完美结合,强大的前后台管理;人性化的界面设计。开放API接口-灵活多动的API,万名开发者召集中。Weiqn 系统开发者AP
1
查看详情
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×6实现为RTX 5090供电750W!甚至都没敢跑分
解决Flask中Quill编辑器内容提交失败及TypeError的指南


2025-12-02
浏览次数:次
返回列表
.Where(u => u.Id == request.Id)
.Select(u => new UserDto(u.Id, u.Name, u.Email))
.FirstOrDefaultAsync(ct);
}
}