使用Mediatr:SaveChanges拦截器触发领域事件VS处理器内直接发布的价值探讨
相比在命令处理器里直接调用await _mediator.Publish(domainEvent),用SaveChanges拦截器触发领域事件能给架构带来这几个关键价值:
保持领域模型的纯粹性
领域事件是领域逻辑的自然产物,应该由实体自身负责产生,而不是依赖应用层的基础设施(比如Mediator)。拦截器模式下,实体只需要把事件添加到自身的事件集合(比如this.AddDomainEvent(new OrderCreatedEvent(Id))),不用关心事件怎么发布、发给谁,彻底隔离业务逻辑和基础设施代码,符合DDD对领域层的隔离要求。保障数据与事件的一致性
拦截器绑定到EF Core的SaveChanges/SaveChangesAsync生命周期,只有当数据库事务提交成功后,事件才会被发布。如果直接在处理器里发布事件,万一后续SaveChanges失败(比如违反数据库约束、连接异常),事件已经发出去了,就会出现「事件说操作完成,但数据库里根本没数据」的不一致问题。拦截器从根源上避免了这种脏事件的产生。消除重复代码
不用在每个命令处理器里手动编写事件发布的代码,所有领域事件的发布逻辑都统一在拦截器里处理。比如创建订单、更新库存、退款等不同业务操作,处理器只需要专注于业务逻辑,不用重复写await _mediator.Publish(...),大幅降低代码冗余和维护成本。实现集中式的事件管控
可以在拦截器里统一对所有领域事件做全局处理:比如添加统一的日志标记、设置事件重试策略、根据环境过滤事件(比如测试环境不发布到外部总线),甚至绑定分布式事务。这些逻辑只需要写一次,就能覆盖所有业务场景,不用在每个处理器里单独实现。
而直接在处理器里发布事件的弊端也很明显:不仅会把领域层和应用层的基础设施耦合死(哪天换事件总线就得改所有处理器),还无法保证事务一致性,很容易引发数据和事件的脱节问题。
内容的提问来源于stack exchange,提问作者Andrew Duffy

