Question

what is the best way to provide bridge between Rebus and NServiceBus applications? with my application, there is a requirement to send/receive messages to my old NServiceBus 2.0 Host.

By dig into a bit, I felt a need of NServiceBusMessageFormatter in Rebus. I'm not sure about direction I am heading to.

Was it helpful?

Solution

I can imagine several solutions for this, and there might be simpler ones than the one I'll describe to you here.

For example, if it's only about providing a one-way messaging channel to your NServiceBus endpoint, you can just spin up a simple Rebus endpoint with an implementation of IHandleMessages<object> that forwards all messages to the NServiceBus endpoint - and that Rebus endpoint could even be hosted inside your old NServiceBus endpoint.

But you state that you need to be able to send/receive messages, which I read as if you need to be able to do request/reply with your NServiceBus endpoint.

To achieve this, I'd treat the NServiceBus endpoint as any other thing, that I would have to integrate with. The NServiceBus endpoint has an asyncronous API though, which means that I'd have to be able to somehow figure out who to reply back to when an NServiceBus reply is received.

This can be achieved in two ways, as I see it:

  1. Slightly modify your NServiceBus endpoint to preserve the original return address as a header on the involved messages.

Do do this, include the rebus-return-address header value with the request sent to your NServiceBus endpoint, and ensure that the endpoint copies this original return address to all replies sent back to your bridge.

This could be done by stashing the original Rebus return address in a custom header on the request, and then use NServiceBus' hooks to ensure that the header is copied to any replies send from your legacy NServiceBus endpoint.

This way, your bridge can do a bus.Advanced.Routing.Send(originalRebusReturnAddress, reply) on received NServiceBus messages in order to explicitly route the reply back to the original requester.

  1. Do all of the housekeeping outside of your legacy endpoint with a saga.

This way, you would come up with a new Guid for each incoming Rebus request and start a saga with that guid inside it, along with the value of the rebus-return-address header from the incoming request. Then you could assign the guid as the NServiceBus correlation ID on the request to your legacy NServiceBus endpoint, which would be automatically copied to all the replies.

Then, back in the bridge, you create a special message wrapper that can be used to forward incoming NServiceBus messages (which must be replies from the legacy endpoint), looking something like this:

public class ForwardedReply 
{
    public Guid CorrelationId { get; set; }

    public object ReplyMessage { get; set; }
}

and then you do something like this in your (only) NServiceBus message handler:

public class BridgeIncomingNsbMessagesToRebus : NServiceBus.IHandleMessages<object>
{
    public Rebus.IBus Bus { get; set; }

    public void Handle(object msg)
    {
        Bus.SendLocal(new ForwardedReply {
            CorrelationId = GetCorrelationIdFrom(msg),
            ReplyMessage = msg
        });
    }
}

This way, your forwarder saga can correlate incoming ForwardedReply messages by their CorrelationId property and have the saga handler send the contents of ReplyMessage back to the original sender, whose address was stored in the saga.

Whoa, that was a long answer - I hope it makes sense to you :) but please, keep in mind that - depending on the messaging exhange patterns you need to be able to use with your legacy endpoint - eveyrything might look simpler (or even more complex ;))

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top