我一直在评估不同的.Net消息传递组件,我在使用MSMQ的Rebus上遇到了一些麻烦,我无法通过文档,示例或谷歌解决这些问题。
我相信我的方案唯一独特之处在于我的客户可以发送或发布消息。看起来应该很简单,但我遇到了以下问题。代码片段遵循这些问题。
的问题:
===========
private void InitializeBus()
{
_messageActivator = new BuiltinHandlerActivator();
Configure.With(_messageActivator)
.Transport(t => t.UseMsmq("publisher"))
.Routing(r => r.TypeBased().Map<MetersRequest>("outgoingMetersRequests")
.Map<CreditAuthorizationRequest>("creditAuthRequests"))
.Start();
}
private async Task SendCreditAuthRequestAsync(int numberToSend)
{
var cardNumber = generateCardNumber();
await _messageActivator.Bus.Send(new CreditAuthorizationRequest(cardNumber));
await WriteOutputAsync($"Sent credit auth request for card {cardNumber}.");
}
private async Task SendMetersRequestAsync(int numberToSend)
{
await _messageActivator.Bus.Send(new MetersRequest());
await WriteOutputAsync("Sent meters request.");
}
===========结束客户
============
private void InitializeBus()
{
_messageActivator = new BuiltinHandlerActivator();
_messageActivator.Register<PosOnlineHandler>(() => new PosOnlineHandler(WriteOutputAsync));
_messageActivator.Register<PumpDownHandler>(() => new PumpDownHandler(WriteOutputAsync));
_messageActivator.Register<MetersRequestHandler>(() => new MetersRequestHandler(WriteOutputAsync, _messageActivator.Bus));
_messageActivator.Register<CreditAuthorizationHandler>(() => new CreditAuthorizationHandler(WriteOutputAsync, _messageActivator.Bus));
Configure.With(_messageActivator)
.Transport(t => t.UseMsmq("subscriber1"))
.Routing(r => r.TypeBased()
.Map<PumpDownEvent>("publisher")
.Map<PosOnlineEvent>("publisher")
.Map<MetersRequest>("outgoingMetersRequests")
.Map<CreditAuthorizationRequest>("creditAuthRequests"))
.Start();
_messageActivator.Bus.Subscribe<PumpDownEvent>().Wait();
_messageActivator.Bus.Subscribe<PosOnlineEvent>().Wait();
}
public class MetersRequestHandler : IHandleMessages<MetersRequest>
{
private readonly Random _randomizer = new Random();
private readonly Func<string, Task> _outputDelegate2;
private readonly IBus _messageBus;
public MetersRequestHandler(Func<string, Task> outputDelegate, IBus messageBus)
{
_outputDelegate2 = outputDelegate;
_messageBus = messageBus;
}
public async Task Handle(MetersRequest message)
{
var pump = _randomizer.Next(20);
var meters = _randomizer.Next();
decimal dollars = (decimal)_randomizer.NextDouble();
var response = new MetersResponse(pump, meters, dollars);
await _outputDelegate2($"Sending MetersResponse: (Pump={pump}) (Meters={meters}) (Dollars ={dollars}");
await _messageBus.Reply(response);
}
}
============
答案 0 :(得分:1)
在您发布的代码中,有几件事情似乎有点不对劲。我只会评论你的问题,然后我会提出一个前进的方法:)
未处理MetersRequest。它们只是在outgoingMetersRequests队列中堆积。
当您致电.Routing(t => t.TypeBased().Map<SomeMessage>("someQueue"))
时,您说Rebus端点的SomeMessage
类型由输入队列someQueue
“拥有”。
当您await bus.Send(yourMessage)
时,Rebus将获得拥有yourMessage
类型的队列并在那里发送消息。这很好地解释了为什么MetersRequest
转到outgoingMetersRequests
队列。
但是,您尚未发布任何显示端点,其中outgoingMetersRequests
队列作为其输入队列的代码。有人需要处理该队列中的消息才能发生某些事情。
“输入队列”是您在.Transport(t => t.UseMsmq("publisher"))
部分中配置的内容 - 在这种情况下,输入队列为publisher
。
收到错误消息,指出creditAuthRequests队列不存在或我没有权限。
是的 - MSMQ错误消息通常不是最好的;)
我已经确认队列没有被创建,但我的假设是Rebus将确保在创建outgoingMetersRequests队列时创建它。
Rebus(使用MSMQ)仅创建输入队列和错误队列(默认情况下称为error
)。这意味着您必须至少使用outgoingMetersRequests
作为其输入队列运行一个端点,或者您是否手动创建了队列?
(旁注:如果我从Bus.Send(...)中删除'await',错误就会消失,但仍然没有创建队列,也没有找到消息。)
错误不会消失 - 异常被捕获并传递给在线程池线程上运行的延续,您永远不会看到它,因为您放弃了从Task
返回的Send
我建议你这样做:
为输入队列提供良好的名称 - publisher
和subscriber
过于通用,您应该首先选择与每个端点的责任或原因相对应的名称。< / p>
注意您的消息类型。您已将此事件命名为事件*Event
,并且您对请求/回复的使用看起来也正确。
使用某种共享订阅存储,例如一个中央SQL Server。这样 - 如果您在所有发布者和订阅者中配置相同的集中订阅存储 - 您的事件类型不需要任何端点映射,这非常简洁。您可以在the wiki page about subscription storages。