NServiceBus.Bridge is a component that allows to connect parts of NServiceBus-based solution that use different transports. Contrary to Gateway and Wormhole, the Bridge handles both sends and publishes and it does so as transparently as possible:
- The endpoint that replies to a message does not have to know if the initiating message came through a bridge. The reply will be automatically routed to the correct bridge and then forwarded to the initiator endpoint.
- The endpoint that publishes events does not have to know if the subscribers are on the other side of the bridge.
|Dedicated routing||Yes, via sites||Yes, via ramp configuration|
The main difference is that the Bridge connects parts of the system that have no logical distinction so the bridging is a purely technical exercise. In other words, if both sides could agree on the same transport technology, the Bridge could be removed without any changes to the logic of the system. Gateways on the other hand are logically significant and the idea of sites has to be taken into account in the logic itself.
The Bridge is in essence a pair of NServiceBus endpoints that forward messages between each other. Regular endpoints connect to the Bridge using ramps that allow them to configure the routing
var config = new EndpointConfiguration("MyEndpoint"); var routing = config.UseTransport<MsmqTransport>().Routing(); var ramp = routing.UseBridgeRamp("LeftBank"); ramp.RouteToEndpoint(typeof(MyMessage), "Receiver"); ramp.RegisterPublisher(typeof(MyEvent), "Publisher");
The snippet above tells the endpoint that a designated Bridge listens on queue
LeftBank and that messages of type
MyMessage should be sent to the endpoint
Receiver on the other side of the Bridge. It also tell the subscription infrastructure that the event
MyEvent is published by the endpoint
Publisher that is hosted on the other side of the bridge.
The following snippet shows a simple MSMQ-to-RabbitMQ Bridge configuration
var config = Bridge .Between<MsmqTransport>("LeftBank") .And<RabbitMQTransport>("RightBank", t => t.ConnectionString("host=localhost"));
The Bridge has a simple life cycle:
var bridge = config.Create(); await bridge.Start().ConfigureAwait(false); await bridge.Stop().ConfigureAwait(false);
Subscribing to an event through a Bridge is always done via a message-driven mechanism similar to the one used by the unicast transports. The subscription message contains additional information about the name of the publisher endpoint and is send to the Bridge instead of the actual publisher.
Publishing an event that is subscribed by an endpoint on the other side of a Bridge does not differ from regular publishing. In fact the publisher does not need to know about the Bridge at all.
The Bridge uses a persistence-based message-driven approach. Each Bridge has a subscription storage. When a subscribe message comes via a ramp, a new entry in the subscription store is created matching the subscriber and the event type. Next, the subscribe request if forwarded to the other side of the Bridge where the execution depends on the type of the transport:
If the transport on the other side supports unicast operations only, the subscribe request is turned into a subscription message that is sent to the ultimate publisher. The subscriber address is the Bridge address so that the Bridge can forward the published events.
If the transport on the other side does support multicast operations, the subscriber request is turned into the native subscribe action. This might result in creation of topics, exchanges or similar structures in the underlying message broker.
The messages traveling through a Bridge can get duplicated along the way. The Bridge does not come with an integrated message deduplication mechanism.
The Bridge does, however, preserve the message ID between the source and the ultimate destination. The message ID can be used to deduplicate at the destination. If the destination endpoint uses the Outbox the deduplication will be done automatically by means of the Outbox mechanism.