是否可以在BeforeTransportMessage事件中提交事务

时间:2014-12-17 11:37:40

标签: rebus

正如标题中我想问的是可以在BeforeTransportMessage事件中提交事务,例如,如果特定标头出现在TransportMessage中,我可以将其包装在另一个消息中并发送到其他地方并停止Rebus进一步处理。

我没有找到使用该事件的真实例子,是否有可能分享的内容?

提前致谢:)

1 个答案:

答案 0 :(得分:1)

如果您可以安全地反序列化所有传入的消息,那么您可以这样做:

如果您正在尝试实施检查所有传入消息的过滤器,我建议您创建一个“全能”消息处理程序,即IHandleMessages<object>的实现。我们称之为CatchAllHandler,虽然我相信你能想出一个更好的名字;)

然后你可以

Configure.With(yourFavoriteContainerAdapter)
    .UseMsmq(...)
    .SpecifyOrderOfHandlers(o => o.First<CatchAllHandler>())
    .Create()
    .Start();

以便在所有其他处理程序之前将所有传入消息分派到CatchAllHandler。由于它实现了IHandleMessage<object>,因此它能够处理所有传入的消息。您的CatchAllHandler可以执行以下操作:

public class CatchAllHandler : IHandleMessages<object> {
    readonly IMessageContext context;
    readonly IBus bus;

    public CatchAllHandler(IMessageContext context, IBus bus) {
        this.context = context;
        this.bus = bus;
    }

    public void Handle(object message) {
        if (MessageHasSpecialHeader(context.Headers)) {
            // forward the current transport message in its entirety
            bus.Advanced.Routing.ForwardCurrentMessage("somewhereElse");

            // abort further processing of the message (i.e. do not
            // dispatch to subsequent handlers in the pipeline)
            context.Abort();
        }
    }

    bool MessageHasSpecialHeader(IDictionary<string, object> headers) {
        // ... look for that special header down here
    }
}

但是,如果您不知道传入的byte[]是否适合您,则需要执行其他操作。虽然在没有Rebus其余部分的情况下使用Rebus的传输实现是相当简单的,但你必须自己实现线程模型。

以下代码是一个示例(完全从内存中编写,因此您可能需要更正一些小部分),如果您使用MSMQ,这样的工作线程可能会是什么样子:

volatile bool _keepWorking = true;

public void ThreadLoop() {
    using(var transport = new MsmqMessageQueue("inputQueueName")) {
        while(_keepWorking) {
            using(var scope = new TransactionScope()) 
            using(var context = new AmbientTransactionContext())
            {
                var message = transport.ReceiveMessage(context);
                if (message == null) {
                    Thread.Sleep(1000); //< don't punish queues too much
                    continue;
                }

                var destination = GetDestinationBasedOnWhatever(message);

                transport.Send(destination, message.ToForwardableMessage());

                scope.Complete();
            }
        }
    }
}

您需要一个单独的队列来处理这种特殊类型的content-based router。你觉得那会对你有用吗?