
In the previous articles, we have seen how to decouple the communication between applications using a Message Broker like RabbitMQ.
When a software system is composed of multiple services that perform different tasks but need to interact with each other to perform processing on the information exchanged, it is very important to make sure to eliminate the point-to-point communication and use a strategy that makes them independent especially when the number of such applications or services increases.
In this scenario, the adoption of a middleware that deals with abstracting the communication between the services involved and allowing our software system to be scalable in terms of components can be very effective.
This solution is called Service Bus.
In literature, we can find many definitions, but we can briefly say that a Service Bus is a software system that allows communication and coordination between heterogeneous services through known patterns for the messaging.

The use of such an architecture establishes that the communication between the entities involved must be only under the responsibility of the bus, and then the services involved should only take care to interface with the bus.
An interesting implementation of a Service Bus for .Net is Rebus.

Rebus is an Open Source library and is defined by its creators as:
“a thing that in a transparent and distributed way enables communication between bounded contexts”
This library is provided as a NuGet package and the configuration of our application to use Rebus is quite immediate because it provides a Configuration API that helps us instantiate the bus in a few steps.
Below we can see the minimum set required to create a working bus:
var bus = Configure.With(handlerActivator)
.Transport(chosenTransport)
.Start();
The With() method receives a message handler as a parameter. This handler can be the BuiltinHandlerActivator provided by Rebus or an Adapter for the IoC Container eventually used in our application.
The Transport() method allows you to choose the transport mechanism and the bus mode which can be:
- Normal: modality, in which the bus can receive messages
- One-Way Client: modality, in which the bus is only capable of sending messages
Before the Start() method, which finalizes the bus configuration, additional optional configurations can be added, such as the Logging, useful to understand what happens in the interaction through the bus or such as the Routing one useful to correctly route the messages to the destination.
Now let’s see how to use Rebus in a simple example consisting of an application that creates a message and sends it to the bus, and another one that consumes this message. For this example, we will see three possible cases with the following transport mechanisms: MSMQ (Microsoft Message Queuing), RabbitMQ and ASB (Azure Service Bus).
Transport with MSMQ
Microsoft Message Queuing is an asynchronous queue-based communication technology made available by Microsoft.
To use MSMQ, you need to enable and install it in the Windows Features, in the Control Panel.

We create two Console Applications and we name them Sender and Receiver and install Rebus and Rebus.Msmq as NuGet packages:

The following code block is relative to the Sender application:
namespace Sender
{
class Program
{
static void Main(string[] args)
{
using (var activator = new BuiltinHandlerActivator())
{
var message = new DemoMessage("Demo Message");
var bus = Configure.With(activator)
.Transport(t => t.UseMsmq("Sender"))
.Routing(r => r.TypeBased().Map<DemoMessage> ("Receiver"))
.Start();
bus.Send(message).Wait();
Console.ReadLine();
}
}
}
}
As we can see, in this example, we use the BuiltinHandlerActivator
provided by Rebus. Next, we create an instance from the DemoMessage class that simply contains a string type field that we will use as message content.
With Transport (t => t.UseMsmq (“Sender”)) we declare the use of MSMQ for message transport and the string “Sender” will be the name of the queue that will be created automatically. We can see that, unlike the basic configuration, we find the optional Routing configuration. Routing in Rebus is used to specify where the message should be sent.
The type of routing used in the example is Type-Based, that is the type of DemoMessage message is intended only for a specific endpoint and in particular to the one that has the queue identified by the string “Receiver”. Finally, the message is sent to the destination:

The following code block is relative to the Receiver application
namespace Receiver
{
class Program
{
static void Main(string[] args)
{
using (var activator = new BuiltinHandlerActivator())
{
activator.Handle<DemoMessage> (async msg =>
{
Console.WriteLine($"Received: {msg.Text}");
});
Configure.With(activator)
.Transport(t => t.UseMsmq("Receiver"))
.Start();
Console.WriteLine("Press [enter] to exit.");
Console.ReadLine();
}
}
}
}
In this case too, a handler is instantiated for the type of message DemoMessage. In the Transport, the use of MSMQ and the name of the queue “Receiver” are declared. This last is the same to which the message of the Sender is forwarded.
As shown in the following image, the contents of the message will be correctly printed.

Trasporto con RabbitMQ
Come abbiamo visto nell’articolo Disaccoppiare la comunicazione con RabbitMQ, RabbitMQ è un message broker che implementa il pattern Publish/Subscribe. Per poter utilizzare RabbitMQ con Rebus basta applicare delle piccole modifiche alle due applicazioni Sender e Receiver oltre ad installare il relativo pacchetto NuGet per il trasporto. Per quanto riguarda il Sender, andremo a modificare il tipo di Transport utilizzando il bus nella modalità One-way, in quanto siamo solo interessati a pubblicare il messaggio:
Transport(t => t.UseRabbitMqAsOneWayClient("amqp://localhost"))
The string passed as a parameter of the function represents the connection string towards the running RabbitMQ instance.
In addition, the message is published on the bus using the Publish () method which exploits the exchange of messages based on RabbitMQ’s Topic.

The topic is automatically defined based on the type of message, as we can see in the figure below:

With regards to Receiver too there are few changes to be made and they are related to the transport: as it must receive the message, we must use the Normal mode of the bus:
Transport(t => t.UseRabbitMq("amqp://localhost", "Receiver"))
The first parameter represents the connection string and the second parameter is the input queue. Once the configuration is complete, we subscribe the Receiver for messages of type DemoMessage
bus.Subscribe<DemoMessage>().Wait();

Transport with Azure Service Bus
Azure’s cloud services also include the Azure Service Bus message broker.
To create an instance of ASB we look for the service on Azure Home:

We create a new namespace being careful to select the Standard version as the Basic version does not support the exchange of Publish / Subscribe messages based on Topic:

Once the container has been deployed, in the Shared access policies section we can get the connection string to be used in the Sender and Receiver applications.
As in the case of RabbitMQ we will only change the type of transport:
Transport(t => t.UseAzureServiceBus(azureServiceBusConnection,"Sender"))
and we will subscribe to the Receiver for messages of type DemoMessage.

Sender

In the end, on the Azure dashboard we can view graphs related to requests and messages exchanged, as well as the queues and topics created for communication between applications.

We have seen how, using the same code and changing only the type of transport, whether it is a message broker instantiated in local or in the cloud, it is possible to make applications interact through a Service Bus.
Rebus also offers other features such as the modeling of Process Managers, also known as Sagas. A saga represents something that evolves over time according to certain triggers. So it’s possible to model this evolution as a sort of state machine whose transitions from one state to another are triggered by the arrival of certain messages.
We will discuss these topics in the next article but, in the meantime, I leave below the link to the repository where you can find the three branches with the examples shown for MSMQ, RabbitMQ and ASB.