.NET分层架构下如何无依赖实现MassTransit Saga模式
干净架构下MassTransit Saga无依赖消息的实现方案
核心思路
让SharedContracts只定义纯数据类,完全不引入MassTransit依赖。通过MassTransit的配置能力,在依赖框架的Messaging层中指定Saga与消息的关联规则,替代让消息实现CorrelatedBy<T>接口的方式。
具体实现步骤
1. 定义纯数据消息(SharedContracts项目)
仅保留业务数据属性,无任何框架依赖:
// SharedContracts/ItemCreated.cs public class ItemCreated { public Guid CorrelationId { get; set; } // 其他业务属性... }
2. 配置Saga关联规则(Messaging项目)
在Saga注册配置中,显式指定从消息属性获取关联ID,无需消息实现MassTransit接口:
// Messaging项目中的MassTransit配置 services.AddMassTransit(x => { x.AddSaga<ImportDataSaga>() .InMemoryRepository(); // 可替换为Redis、Entity Framework等持久化方式 x.UsingRabbitMq((context, cfg) => { cfg.ConfigureEndpoints(context); cfg.ReceiveEndpoint("import-data-saga", e => { e.ConfigureSaga<ImportDataSaga>(context, sagaCfg => { // 指定从ItemCreated的CorrelationId属性提取关联ID sagaCfg.CorrelateBy<ItemCreated>(m => m.CorrelationId) .SelectId(m => NewId.NextGuid()); // 初始化Saga的CorrelationId }); }); }); });
3. 实现Saga类(Messaging项目)
Saga正常实现ISaga和消息处理接口,消息本身无框架依赖:
// Messaging/ImportDataSaga.cs public class ImportDataSaga : ISaga, InitiatedBy<ItemCreated> { public Guid CorrelationId { get; set; } public Task Consume(ConsumeContext<ItemCreated> context) { // 业务逻辑处理,可通过context.Message.CorrelationId获取关联ID return Task.CompletedTask; } }
扩展:自定义关联属性名称
如果消息中不想用CorrelationId作为属性名,比如用ImportJobId,只需调整配置和消息定义:
// SharedContracts/ItemCreated.cs public class ItemCreated { public Guid ImportJobId { get; set; } } // 配置中的关联规则修改 sagaCfg.CorrelateBy<ItemCreated>(m => m.ImportJobId) .SelectId(m => m.ImportJobId); // 直接用消息的ImportJobId作为Saga的关联ID
架构合规性说明
- SharedContracts:保持纯数据模型,完全独立于框架,符合干净架构中“核心域与框架解耦”的原则。
- Messaging层:集中处理框架相关配置,作为基础设施层的一部分,隔离了框架细节对业务域的影响。
- 关注点分离:消息的业务定义与框架关联逻辑完全解耦,后续替换消息框架或修改关联规则无需改动核心业务代码。
内容的提问来源于stack exchange,提问作者Petr Klekner
相关产品推荐
相关产品推荐

