This sample shows how to use the NServiceBus Messaging Bridge instead of the deprecated SQL Server transport multi-instance mode.
Prerequisites
Ensure an instance of SQL Server (Version 2016 or above for custom saga finders sample, or Version 2012 or above for other samples) is installed and accessible on localhost
and port 1433
. A Docker image can be used to accomplish this by running docker run -e 'ACCEPT_EULA=Y' -e 'MSSQL_SA_PASSWORD=yourStrong(!)Password' -p 1433:1433 -d mcr.
in a terminal.
Alternatively, change the connection string to point to different SQL Server instance.
At startup each endpoint will create its required SQL assets including databases, tables, and schemas.
The databases created by this sample are NsbSamplesSqlMultiInstanceReceiver
and NsbSamplesSqlMultiInstanceSender
.
Running the project
Start the following projects:
- Sender
- Receiver
- Bridge
Press enter in the Sender's console window to send a new message.
Verifying that the sample works correctly
- The Receiver displays information that an order was submitted.
- The Sender displays information that a response arrived for the same order.
Code walk-through
The sample contains the following projects:
- Sender: A console application responsible for sending the initial
ClientOrder
message and processing the follow-upClientOrderResponse
message. - Receiver: A console application responsible for processing the order message.
- Bridge: A console application responsible for routing messages across the two database instances.
- Messages: A class library containing message definitions.
- Helpers: A class library for creating the databases and schemas.
Sender project
The sender does not store any data. It mimics a front-end system where orders are submitted by the users and passed via the bus to the back-end. It is configured to use the SQL Server transport. Other than that, it is unaware the other endpoint is running on a different database instance.
var endpointConfiguration = new EndpointConfiguration("Samples.SqlServer.MultiInstanceSender");
var transport = endpointConfiguration.UseTransport<SqlServerTransport>();
transport.ConnectionString(ConnectionString);
endpointConfiguration.UseSerialization<SystemJsonSerializer>();
endpointConfiguration.EnableInstallers();
transport.Routing().RouteToEndpoint(typeof(ClientOrder), "Samples.SqlServer.MultiInstanceReceiver");
The sender sends a message to the receiver:
var order = new ClientOrder
{
OrderId = Guid.NewGuid()
};
await messageSession.Send(order);
Receiver project
The receiver mimics a back-end system. It is configured to use the SQL Server transport but has a different connection string from the sender.
var endpointConfiguration = new EndpointConfiguration("Samples.SqlServer.MultiInstanceReceiver");
var transport = endpointConfiguration.UseTransport<SqlServerTransport>();
transport.ConnectionString(ConnectionString);
endpointConfiguration.UseSerialization<SystemJsonSerializer>();
endpointConfiguration.EnableInstallers();
The endpoint configuration contains no routing information. The receiver responds to the sender with a
ClientOrderResponse
message using the Reply method. Using this method, NServiceBus, together with the bridge, handles the routing of reply messages without any additional configuration.
Bridge
The bridge is configured with two transports. As both transports are of the same SqlServerTransport
type, it is required to provide a name to each BridgeTransport
to distinguish between the two in log files.
var receiverTransport = new BridgeTransport(new SqlServerTransport(ReceiverConnectionString))
{
Name = "Receiver",
AutoCreateQueues = true
};
receiverTransport.HasEndpoint("Samples.SqlServer.MultiInstanceReceiver");
var senderTransport = new BridgeTransport(new SqlServerTransport(SenderConnectionString))
{
Name = "Sender",
AutoCreateQueues = true
};
senderTransport.HasEndpoint("Samples.SqlServer.MultiInstanceSender");
bridgeConfiguration.AddTransport(receiverTransport);
bridgeConfiguration.AddTransport(senderTransport);
// .NET 6 does not support distributed transactions
bridgeConfiguration.RunInReceiveOnlyTransactionMode();
Each transport configured in the bridge defines the endpoints it supports on its end. The bridge then creates corresponding shadow endpoints on the opposite side, effectively mirroring them. This setup allows messages to flow seamlessly across the transports without requiring the actual sender or receiver to be aware that bridging is occurring—their communication appears direct and uninterrupted.