Monday, 18 October 2021

RabbitMQ in .NET Core

 RabbitMQ is a most popular and widely used open source message broker software. It supports multiple protocols AMQP, STOMP, MQTT, HTTP and WebSockets. Read more about these protocols here.

RabbitMQ is lightweight and can be easily deployed on premises and in the clouds. RabbitMQ is available on Microsoft azure as “RabbitMQ Server” as well as “RabbitMQ as a Service”. It also supports container based hosting environment and I love it and this is what I’m gonna explain here that How easy it is to make it running.

Before we start, you would need Docker Desktop application running on your system. Once you have the docker desktop application, switch to Linux containers and follow the below steps to write your first simple RabbitMQ message brokering application.

Step 1: Pull and host the docker image. Open the powershell command prompt and run the command:

docker run -it --rm --name rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq:3.9-management

Above command will run host the docker rabbitmq image under localhost:5672 port which uses amqp protocol and the rabbitmq management portal under localhost:15672 which uses http protocol.

Test the RabbitMQ server by browsing rabbitmq management portal: http://localhost:15672/#/

Note: the default userid and password of the portal would be “guest” and “guest”.

Step 2: We are all set with RabbitMQ server hence Lets begin with simple sender and receiver application. Sender will publish a message to a queue and receiver will read it from the same queue.

For this, Lets create two simple .Net 5 console application and name it RabbitMQSender and RabbitMQReceiver.

Step 3: Install RabbitMQ.Client nuget package from nuget store.

Step 3: Now Use the below code to create the sender under RabbitMQSender project which will publish messages to a queue named “hello”.

using RabbitMQ.Client;
using System;
using System.Text;
namespace RabbitMQSender
{
class Sender
{
static void Main(string[] args)
{
var factory = new ConnectionFactory() { HostName = "localhost" };
using (var connection = factory.CreateConnection())
{
Console.WriteLine("Enter command 'exit' to stop sending meesages");
string message = string.Empty;
do
{
SendMessage(connection, message);
Console.Write("Enter your next message:");
message = Console.ReadLine();
} while (!message.Equals("exit", StringComparison.OrdinalIgnoreCase));
}
}
private static void SendMessage(IConnection connection, string message)
{
if (string.IsNullOrEmpty(message))
return;
using (var channel = connection.CreateModel())
{
channel.QueueDeclare(queue: "hello",
durable: false,
exclusive: false,
autoDelete: false,
arguments: null);
var body = Encoding.UTF8.GetBytes(message);var properties = channel.CreateBasicProperties();
properties.Persistent = true;
channel.BasicPublish(exchange: "",
routingKey: "hello",
basicProperties: properties,
body: body);
Console.WriteLine(" [x] Sent {0}", message);
}
}
}
}

Above code is simple where we are:
i. creating a connection factory pointing to localhost:5672 (since 5672 is default reserved port for RabbitMQ hence we don’t need to mention in the code as hostname).
ii. establish the connection (var connection = factory.CreateConnection()).
iii. create the channel, session and model (var channel = connection.CreateModel()).
iv. Declare a queue where message will be published (channel.QueueDeclare).
v. publish the message (channel.BasicPublish).

To make sure the message will be delivered to the receiver whenever he comes i’m making it persistent. Properties will also allows you to define the contentType, ContentEncoding, DeliveryMethod, Expiraiton etc.

var properties = channel.CreateBasicProperties();properties.Persistent = true;

Step 4: Use the below code to create the receiver under RabbitMQReceiver project.

using RabbitMQ.Client;
using RabbitMQ.Client.Events;

using System;
using System.Text;
namespace RabbitMQReceiver
{
class Receiver
{
public static void Main()
{
var factory = new ConnectionFactory() { HostName = "localhost" };
using (var connection = factory.CreateConnection())
{
using (var channel = connection.CreateModel())
{
channel.QueueDeclare(queue: "hello",
durable: false,
exclusive: false,
autoDelete: false,
arguments: null);
var consumer = new EventingBasicConsumer(channel);
consumer.Received += (model, ea) =>
{
var body = ea.Body.ToArray();
var message = Encoding.UTF8.GetString(body);
Console.WriteLine(" [x] Received {0}", message);
channel.BasicAck(deliveryTag: ea.DeliveryTag, multiple: false);
};
channel.BasicConsume(queue: "hello",
autoAck: false,//making it false as we are doing it manually above
consumer: consumer);
Console.WriteLine(" Press [enter] to exit.");
Console.ReadLine();
}
}
}
}
}

Here too we are following the same process till creating the channel, session and model then declaring the queue. This will be having the same queue which you named for the sender’s queue as this has to listen the message for the same queue.

Once above is done we create the consumer and add the consumer’s Received event and that is where we read the published messages from sender and send back a acknowledgment to the sender. Here instead of RabbitMQ default message acknowledgment feature, I’m doing it manually after I read the message.

channel.BasicAck(deliveryTag: ea.DeliveryTag, multiple: false);

Now you can run both the program and test it. you can run multiple Receivers at a time and RabbitMQ will deliver the message to the active receivers one at a time based on default Round Robin method.

Note: if you would have noticed, I have used exchange=”” publishing the message in sender and it used RabbitMQ’s default Direct exchange protocol which publish the method to one queue at a time. if we need to publish the message for multiple queues then we need to user other exchange protocol as “Topic” or “Fanout”.

Thanks for reading. Happy RabbitMQueuing.

No comments:

Post a Comment