Windows Services 中 NServiceBus subscription 不工作
结论
Subscriber 的 Bus Setup 中缺少 .LoadMessageHandlers()。
旧版 NServiceBus 需要先加载并扫描消息处理器,才能发现 IHandleMessages<T> 的实现,并根据 MessageEndpointMappings 自动向 Publisher 发送订阅请求。当前配置虽然启动了总线,但没有加载 handler,因此不会完成自动订阅,也看不到订阅成功的日志。
修正 Subscriber 配置
在 .UnicastBus() 后调用 .LoadMessageHandlers():
var bus = Configure.With()
.Log4Net()
.NinjectBuilder()
.XmlSerializer()
.MsmqSubscriptionStorage()
.MsmqTransport()
.IsTransactional(false)
.PurgeOnStartup(false)
.UnicastBus()
.LoadMessageHandlers()
.ImpersonateSender(false)
.CreateBus()
.Start();
还要确认 Subscriber 中确实存在对应事件的 handler,例如:
public class MyEventHandler : IHandleMessages<MyEvent>
{
public void Handle(MyEvent message)
{
// 处理事件
}
}
如果没有实现 IHandleMessages<MyEvent>,即使配置了 MessageEndpointMappings,NServiceBus 也找不到需要自动订阅的事件类型。
MessageEndpointMappings
Subscriber 需要声明事件由哪个 Publisher 发布,现有配置的方向没有问题:
<UnicastBusConfig>
<MessageEndpointMappings>
<add Messages="MyEventNamespace"
Endpoint="publisher.input" />
</MessageEndpointMappings>
</UnicastBusConfig>
如果 Publisher 位于另一台机器,端点中需要包含机器名:
<add Messages="MyEventNamespace"
Endpoint="publisher.input@PublisherMachine" />
同时确认 Messages 指向事件类型所在的正确命名空间。某些旧版本也支持使用程序集限定的映射,具体格式取决于当前使用的 NServiceBus 版本。
Publisher 通常不需要为自己发布的事件配置 MessageEndpointMappings。这项配置主要用于告诉 Subscriber 应向哪个端点发送订阅请求。
还需要检查的项目
如果加入 .LoadMessageHandlers() 后仍未订阅,可以继续检查:
- handler 所在的程序集是否已被
Configure.With()扫描。如果 handler 位于单独的程序集,需要确保该程序集已经加载,必要时显式传给Configure.With(...)。 - 事件类型对 NServiceBus 而言是否确实属于消息。根据所用的旧版本,它通常需要实现相应的标记接口,例如:
public class MyEvent : IEvent
{
}
publisher.input和subscriber.input队列是否存在,以及 Windows Service 账户是否拥有 MSMQ 的发送和接收权限。- Publisher 与 Subscriber 是否引用同一个消息契约程序集,避免两端使用名称相似但 CLR 类型不同的事件。
- Publisher 的订阅存储配置是否可用。这里使用的是:
.MsmqSubscriptionStorage()
这项配置主要由 Publisher 使用,用于保存订阅信息。
当前配置中最直接的问题是 Subscriber 没有调用 .LoadMessageHandlers()。加载 handler 后,NServiceBus 才能发现订阅需求并完成自动订阅。
备注:内容仅供参考。
