当前位置: 首页
编程语言
c#如何使用MediatR_c#MediatR的正确用法与注意事项

c#如何使用MediatR_c#MediatR的正确用法与注意事项

热心网友 时间:2026-05-06
转载

C#中MediatR的正确用法与核心注意事项

c#如何使用MediatR_c#MediatR的正确用法与注意事项

免费影视、动漫、音乐、游戏、小说资源长期稳定更新! 👉 点此立即查看 👈

在C#项目里引入MediatR,本意是让代码更清晰、更解耦。但实际操作中,不少开发者第一步就卡住了——如果没正确注册IMediator,或者注册方式有偏差,那么后续所有的Send操作都会直接抛出InvalidOperationException,让你寸步难行。

Program.cs 里怎么注册才不报错

问题的根源往往在服务注册这一步。必须调用AddMediatR,但仅仅写builder.Services.AddMediatR()是远远不够的(尤其是在.NET 6+的默认参数下,很容易漏掉跨程序集的Handler)。一个常见的坑是只传入了当前入口程序集,而Handler实际却定义在另一个类库中。

  • 场景一:Handler和请求类都在主项目(比如一个Web API)。这时应该用AddMediatR(cfg => cfg.RegisterServicesFromAssembly(typeof(Program).Assembly)),明确指定从当前程序集加载。
  • 场景二:Handler单独放在ApplicationHandlers类库中。这就必须显式传入那个类库的程序集,例如AddMediatR(typeof(CreateUserCommandHandler).Assembly)
  • 别忘了using MediatR;——少了这个命名空间,AddMediatR扩展方法压根不会出现在智能提示里。
  • 生命周期配置是关键。通常需要加上.AsScoped()(或者确保默认就是Scoped)。因为MediatR内部依赖IServiceProvider来解析Handler,而Handler往往需要注入像DbContext这类Scoped服务。生命周期不匹配,程序运行起来很容易“炸”。

IRequest 和 IRequest 怎么选

选错接口类型,轻则编译失败,出现Cannot convert lambda expression这类错误;重则运行时逻辑混乱,比如Send一个本该返回void的请求,却试图去接收返回值。

  • 纯触发动作,不关心结果:比如发送邮件、记录日志。直接用IRequest,对应的Handler签名是Task Handle(...)
  • 需要返回数据:比如创建实体后返回ID,或者查询后返回一个DTO。那就必须用IRequestIRequest这类泛型接口,Handler签名相应是Task Handle(...)
  • 有一个绝对要避免的写法:不要用void作为泛型参数IRequest是不合法的,编译直接通不过。
  • 另外,命令类(Command)里最好别塞[Required]这类数据注解属性来做验证。验证逻辑应该交给IRequestPreProcessor或者专门的验证库(如FluentValidation)来处理,这样职责更清晰。

Handler 里为什么不能混读写逻辑

想象一下,在一个GetUserQueryHandler里,你顺手调用了_context.Sa veChangesAsync()。代码可能能跑起来,但这实际上破坏了CQRS(命令查询职责分离)的隔离前提,会引发一系列连锁问题:缓存失效、事务锁表,甚至导致本该快速的读接口变得异常缓慢。

  • Query Handler 只负责读:应该使用IUserReadRepository这类只读仓储,或者至少用DbSet.AsNoTracking()来确保不跟踪变更。严格禁止任何形式的Sa veChangesAsync调用。
  • Command Handler 只负责改状态:它的职责是改变领域状态,通常不应该返回完整的Entity对象(这容易意外触发EF Core的延迟加载或序列化时的循环引用问题)。更合适的做法是返回ID、精简的DTO,或者直接返回Unit.Value
  • 从设计上就避免混淆:不要让一个Handler类同时实现IRequestHandlerIRequestHandler。类型系统虽然允许,但这在语义上已经违背了CQRS的核心思想。
  • 当然,读写操作可以共用同一个DbContext实例(只要Scoped生命周期配置合理)。但关键在于,读写逻辑必须在代码层面严格分层,不能仅仅依靠开发者的“自觉”来隔离。

领域事件该用 IPublisher 还是 IMediator

如果你用IMediator.Publish()来发布领域事件,很可能会遇到事务一致性问题。因为IMediator并不感知EF Core的Unit of Work(工作单元),事件可能在数据库事务提交之前就被发出去了,导致数据状态不一致。

  • 正确的选择是IPublisher:这是MediatR专门提供的接口。它与EF Core的事务拦截器可以协同工作,确保事件只在Sa veChangesAsync成功执行后才真正发布出去。
  • IPublisher本身也是Scoped生命周期,直接从依赖注入容器中获取即可,千万不要自己去new实例。
  • 注意事件类的定义:它必须继承INotification,而不是IRequest。对应的Handler则需要实现INotificationHandler
  • 还有一个实践细节:不建议在Command Handler里直接await _publisher.Publish(...)之后再return。因为事件发布的失败不应该阻塞主业务流程。更稳健的做法是采用fire-and-forget(触发后不管)模式,或者用后台队列来兜底。

最后,需要时刻牢记一点:CQRS的区分,靠的不是类名,而是Handler的实际行为。哪怕你给类起名叫GetUserQuery,只要它在里面调用了Sa veChanges,那它本质上就已经不是一个Query了。这才是理解MediatR和CQRS模式的关键所在。

来源:https://www.php.cn/faq/2315573.html

游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。

同类文章
更多
怎么利用 System.err 输出错误流并在控制台中以醒目的颜色标记(取决于终端)

怎么利用 System.err 输出错误流并在控制台中以醒目的颜色标记(取决于终端)

怎么利用 System err 输出错误流并在控制台中以醒目的颜色标记(取决于终端) System err 默认行为不带颜色,终端是否显示颜色取决于自身支持 首先得明确一点:System err 本质上只是 Ja va 标准库里的一个 PrintStream 对象。它本身并不负责“颜色”这种花哨的玩

时间:2026-05-06 09:59
如何在 Java 中使用 ThreadLocal.remove() 确保在线程池复用场景下不会发生数据污染

如何在 Java 中使用 ThreadLocal.remove() 确保在线程池复用场景下不会发生数据污染

如何在 Ja va 中使用 ThreadLocal remove() 确保在线程池复用场景下不会发生数据污染 说到线程池和 ThreadLocal 的搭配使用,一个看似不起眼、实则极易“踩坑”的细节就是数据清理。想象一下,你精心设计的线程池正在高效运转,却因为某个任务留下的“数据尾巴”,导致后续任务

时间:2026-05-06 09:59
怎么利用 Arrays.asList() 转换出的“受限列表”理解其对 add() 等修改操作的限制

怎么利用 Arrays.asList() 转换出的“受限列表”理解其对 add() 等修改操作的限制

Arrays asList():一个“受限”但实用的列表视图 在Ja va开发中,Arrays asList()是一个高频使用的方法,但你是否真正了解它返回的是什么?一个常见的误解是,它直接生成了一个标准的ArrayList。事实并非如此。 简单来说,Arrays asList()返回的并非我们熟悉

时间:2026-05-06 09:59
如何在 Java 中利用 try-catch 实现对“软错误”的平滑感知与非侵入式监控日志记录

如何在 Java 中利用 try-catch 实现对“软错误”的平滑感知与非侵入式监控日志记录

如何在 Ja va 中利用 try-catch 实现对“软错误”的平滑感知与非侵入式监控日志记录 在 Ja va 开发中,我们常常会遇到一些“软错误”——它们不会让程序直接崩溃,却可能悄悄影响业务的正确性或用户体验。比如,调用第三方 API 时返回了空响应、缓存查询未命中、配置文件里某个非关键项缺失

时间:2026-05-06 09:59
Django怎么防止Celery任务重复执行_Python结合Redis实现分布式锁

Django怎么防止Celery任务重复执行_Python结合Redis实现分布式锁

Django怎么防止Celery任务重复执行:Python结合Redis实现分布式锁 你遇到过吗?明明只发了一次任务,后台却执行了两次。这不是代码写错了,而是分布式环境下一个经典的老朋友:多个worker同时抢到了同一个活儿。 为什么Celery任务会重复执行 问题的根源在于竞争。想象一下,多个Ce

时间:2026-05-06 09:58
热门专题
更多
刀塔传奇破解版无限钻石下载大全 刀塔传奇破解版无限钻石下载大全
洛克王国正式正版手游下载安装大全 洛克王国正式正版手游下载安装大全
思美人手游下载专区 思美人手游下载专区
好玩的阿拉德之怒游戏下载合集 好玩的阿拉德之怒游戏下载合集
不思议迷宫手游下载合集 不思议迷宫手游下载合集
百宝袋汉化组游戏最新合集 百宝袋汉化组游戏最新合集
jsk游戏合集30款游戏大全 jsk游戏合集30款游戏大全
宾果消消消原版下载大全 宾果消消消原版下载大全
  • 日榜
  • 周榜
  • 月榜
热门教程
更多
  • 游戏攻略
  • 安卓教程
  • 苹果教程
  • 电脑教程