如何在不同程序集间用Rebus发布订阅相同DTO?
解决Rebus跨程序集同名类型的发布订阅问题
你的问题核心是Rebus默认使用类型全名, 程序集名称作为消息的唯一标识,导致订阅端试图加载发布端程序集A中的TYPEA,从而抛出格式异常。通过自定义IMessageTypeNameConvention,可以实现仅用命名空间+类型名作为消息标识,无需共享程序集。
自定义消息类型命名约定
实现IMessageTypeNameConvention接口,剥离程序集信息,仅保留命名空间和类型名:
public class NamespaceOnlyTypeNameConvention : IMessageTypeNameConvention { public string GetMessageTypeName(Type type) { // 返回命名空间+类型名,不包含程序集信息 return $"{type.Namespace}.{type.Name}"; } public Type GetTypeFromMessageTypeName(string messageTypeName) { // 在当前程序集中查找匹配的类型 return Type.GetType(messageTypeName, throwOnError: true); } }
在两端配置Rebus
发布端和订阅端都需要替换默认的消息命名约定,确保两端使用相同的规则解析消息类型:
发布端配置示例
// 示例使用内置激活器和RabbitMQ传输,可根据实际情况替换 var publisherActivator = new BuiltinHandlerActivator(); Configure.With(publisherActivator) .Transport(t => t.UseRabbitMq("amqp://localhost", "publisher-queue")) .MessageNaming(m => m.UseCustomMessageTypeNameConvention(new NamespaceOnlyTypeNameConvention())) .Start();
订阅端配置示例
var subscriberActivator = new BuiltinHandlerActivator(); // 注册TYPEA的消息处理程序 subscriberActivator.Register(() => new TypeAHandler()); Configure.With(subscriberActivator) .Transport(t => t.UseRabbitMq("amqp://localhost", "subscriber-queue")) .Subscriptions(s => s.UseJsonFile(@"subscriptions.json")) .MessageNaming(m => m.UseCustomMessageTypeNameConvention(new NamespaceOnlyTypeNameConvention())) .Start(); // 订阅TYPEA消息 await subscriberActivator.Bus.Subscribe<TypeA>();
关键注意事项
- 两端的TYPEA类型必须结构完全一致:字段/属性的名称、类型、可访问性都要匹配,否则序列化/反序列化会失败。
- 确保两端使用的序列化器配置相同(比如用Newtonsoft.Json时,统一日期格式、空值处理等规则)。
- 避免不同业务逻辑的类型使用完全相同的命名空间+类型名,防止消息路由混乱。
内容的提问来源于stack exchange,提问作者Massimo Lavermicocca
相关产品推荐
相关产品推荐

