RabbitMQ
.NET
Publish/Subscribe
Messaging Systems
Programming Languages

Publish/Subscribe samples with RabbitMQ in .NET

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

RabbitMQ is an open-source message broker that enables applications to communicate with each other asynchronously by sending messages through an exchange to a queue. It supports multiple messaging protocols, one of which is AMQP (Advanced Message Queuing Protocol). In the .NET ecosystem, RabbitMQ can be manipulated using the official RabbitMQ .NET client library. One common messaging pattern with RabbitMQ is Publish/Subscribe (pub-sub), which allows messages to be broadcasted to multiple receivers. In this article, we will explore how you can implement the Publish/Subscribe pattern using RabbitMQ in .NET.

Understanding the Publish/Subscribe Pattern

The Publish/Subscribe pattern involves three primary components:

  • Publisher: Sends messages to an exchange, without knowing the recipients of the message.
  • Exchange: Receives messages from the publisher and routes them to appropriate queues.
  • Subscribers (Consumers): Receives messages from queues.

Messages sent by the publisher are transient and don't get saved unless there is at least one active subscriber. The exchange decides how to route a message to queues using various exchange types, such as direct, topic, headers, and fanout.

Setting Up the Environment

Before implementing the pattern, you need to set up RabbitMQ on your system. You can install RabbitMQ server through its official website or use Docker. Then, ensure you have a .NET development environment ready, and install the RabbitMQ client for .NET by adding the RabbitMQ.Client package to your project:

 
dotnet add package RabbitMQ.Client

Publish/Subscribe Implementation in .NET

Publisher Code

A publisher application creates an exchange, and sends messages to this exchange:

csharp
1using RabbitMQ.Client;
2using System.Text;
3
4class Publisher
5{
6    public static void Main()
7    {
8        var factory = new ConnectionFactory() { HostName = "localhost" };
9        using (var connection = factory.CreateConnection())
10        {
11            using (var channel = connection.CreateModel())
12            {
13                channel.ExchangeDeclare(exchange: "logs", type: "fanout");
14
15                string message = "Hello World!";
16                var body = Encoding.UTF8.GetBytes(message);
17
18                channel.BasicPublish(exchange: "logs", routingKey: "",
19                                     basicProperties: null, body: body);
20                Console.WriteLine(" [x] Sent {0}", message);
21            }
22        }
23    }
24}

Subscriber Code

Subscribers listen for messages from a specific queue which is bound to an exchange:

csharp
1using RabbitMQ.Client;
2using RabbitMQ.Client.Events;
3using System;
4using System.Text;
5
6class Subscriber
7{
8    public static void Main()
9    {
10        var factory = new ConnectionFactory() { HostName = "localhost" };
11        using (var connection = factory.CreateConnection())
12        using (var channel = connection.CreateModel())
13        {
14            channel.ExchangeDeclare(exchange: "logs", type: "fanout");
15            
16            var queueName = channel.QueueDeclare().QueueName;
17            channel.QueueBind(queue: queueName, exchange: "logs", routingKey: "");
18
19            var consumer = new EventingBasicConsumer(channel);
20            consumer.Received += (model, ea) =>
21            {
22                var body = ea.Body.ToArray();
23                var message = Encoding.UTF8.GetString(body);
24                Console.WriteLine(" [x] Received {0}", message);
25            };
26            channel.BasicConsume(queue: queueName, autoAck: true, consumer: consumer);
27
28            Console.WriteLine(" Press [enter] to exit.");
29            Console.ReadLine();
30        }
31    }
32}

Key Considerations and Best Practices

ConsiderationDescription
Exchange TypeChoose the right exchange type based on the routing behavior needed."> For broad broadcasting to all consumers, use fanout.
Message DurabilityIf you need messages to be persistent, configure both the messages and the queues to be durable.
Error HandlingImplement error handling in your consumer application to deal with faulty messages.
Consumer AcknowledgmentDecide whether you need automatic or manual acknowledgment for better message processing control.

Conclusion

Implementing the Publish/Subscribe pattern with RabbitMQ in .NET is straightforward thanks to the robust library provided by RabbitMQ. With the fanout exchange type, you can easily broadcast messages to multiple subscribers, which adds scalability and flexibility to your applications. By understanding and utilizing different configurations and acknowledging the best practices, you can build efficient and reliable message-based systems in .NET with RabbitMQ.


Course illustration
Course illustration

All Rights Reserved.