Shape the future of .NET tooling by spending just 10 minutes on JetBrainsâ .NET development market research. Fill out the survey and enter the prize draw! Start now
Whether you're building microservices or just want to offload work from your main app, RabbitMQ is one of the best tools to help you get there.
RabbitMQ is a message broker. Think of it like a reliable postal service for your software.
Instead of one system directly calling another (which creates tight coupling), RabbitMQ acts as the middleman:
This is called asynchronous communication, and itâs great for performance, reliability, and scalability.
Key Components:
You can install RabbitMQ using Docker:
docker run -d --hostname rabbitmq --name rabbitmq \ -p 5672:5672 -p 15672:15672 rabbitmq:3-management
Letâs build a simple project:
Through this example I'm going to explain how it works.
Firstly, you need to add RabbitMQ library to your project:
Install-Package RabbitMQ.Client
Letâs define a C# class to represent an email message:
public class EmailMessage{ public string To { get; set; } = default!; public string Subject { get; set; } = default!; public string Body { get; set; } = default!;}
Publisher
The Publisher is the part of your app that sends messages to RabbitMQ.
Its Job:
Real-World Analogy:
Think of it like dropping a letter into a mailbox. Youâre not handling the delivery - just making sure it gets into the system.
public class EmailMessagePublisher{ private const string EmailQueue = "email-queue";Â public async Task Publish(EmailMessage email) { var factory = new ConnectionFactory() { HostName = "localhost" }; using var connection = await factory.CreateConnectionAsync(); using var channel = await connection.CreateChannelAsync();Â // Ensure the queue exists await channel.QueueDeclareAsync(queue: EmailQueue, durable: true, exclusive: false, autoDelete: false, arguments: null);Â // Create a message var message = JsonSerializer.Serialize(email); var body = Encoding.UTF8.GetBytes(message);Â // Publish the message await channel.BasicPublishAsync( exchange: string.Empty, routingKey: EmailQueue, mandatory: true, basicProperties: new BasicProperties { Persistent = true }, body: body); }}
Parameters:
Receiver
The Receiver listens to the queue and processes messages as they arrive.
Its Job:
Real-World Analogy:
Think of it like a mailroom clerk who monitors the inbox and acts whenever a new letter shows up.
public class EmailMessageConsumer : BackgroundService{ private const string EmailQueue = "email-queue";Â protected override async Task ExecuteAsync(CancellationToken stoppingToken) { var factory = new ConnectionFactory() { HostName = "localhost" }; using var connection = await factory.CreateConnectionAsync(stoppingToken); using var channel = await connection.CreateChannelAsync(cancellationToken: stoppingToken);Â await channel.QueueDeclareAsync(queue: EmailQueue, durable: true, exclusive: false, autoDelete: false, arguments: null, cancellationToken: stoppingToken);Â var consumer = new AsyncEventingBasicConsumer(channel); consumer.ReceivedAsync += async (sender, eventArgs) => { var body = eventArgs.Body.ToArray(); var json = Encoding.UTF8.GetString(body); var email = JsonSerializer.Deserialize<EmailMessage>(json);Â Console.WriteLine($"Sending Email To: {email?.To}, Subject: {email?.Subject}");Â // Simulate sending email... Task.Delay(1000).Wait();Â await ((AsyncEventingBasicConsumer)sender).Channel.BasicAckAsync(eventArgs.DeliveryTag, multiple: false); };Â await channel.BasicConsumeAsync(queue: EmailQueue, autoAck: true, consumer: consumer, cancellationToken: stoppingToken); }}
An Exchange in RabbitMQ is like a post office: it decides where to send the message. Each exchange type has a different strategy for routing messages.
Here are the 4 main types:
Headers
Direct Exchange (One-to-One Routing)
Example Use Case: You want to send emails only to a queue responsible for âwelcomeâ emails.
.NET Setup:
channel.ExchangeDeclare("direct-exchange", ExchangeType.Direct);channel.QueueBind("email-welcome-queue", "direct-exchange", "welcome");
If you publish with routingKey = "welcome", it will go to email-welcome-queue.
Example Use Case: You want to send a system-wide notification to all services (email, SMS, push).
.NET Setup:
channel.ExchangeDeclare("fanout-exchange", ExchangeType.Fanout);channel.QueueBind("email-queue", "fanout-exchange", "");channel.QueueBind("sms-queue", "fanout-exchange", "");
Any message sent to "fanout-exchange" goes to both queues.
Wildcards
Example Use Case: Route logs based on severity and system.
.NET Setup:
channel.ExchangeDeclare("topic-exchange", ExchangeType.Topic);channel.QueueBind("error-queue", "topic-exchange", "log.error.#");channel.QueueBind("auth-queue", "topic-exchange", "log.*.auth");
"log.error.auth" goes to both queues. "log.info.auth" goes to auth-queue. "log.error.database" goes to error-queue.
Example Use Case: Route messages with complex conditions (e.g., "x-type": "invoice" and "region": "EU")
.NET Setup:
channel.ExchangeDeclare("headers-exchange", ExchangeType.Headers);Â var args = new Dictionary<string, object>{ { "x-match", "all" }, // or "any" { "x-type", "invoice" }, { "region", "EU" }};Â channel.QueueBind("invoice-eu-queue", "headers-exchange", string.Empty, args);
Only messages that include both x-type=invoice and region=EU in their headers will be routed.
When to Use Which Exchange?
Direct - Exact one-to-one message routing Fanout - Broadcasting to multiple consumers Topic - Flexible, pattern-based routing (e.g., logs) Headers - Complex routing based on multiple conditions
For alternative messaging solutions, check out Redis Pub/Sub Messaging and NATS Real-Time Messaging.
RabbitMQ is a powerful tool for building scalable, decoupled systems - and .NET makes it surprisingly easy to integrate with.
Whether you're building microservices or just want to offload some long-running tasks, RabbitMQ has your back.
That's all from me today.
P.S. Follow me on YouTube.
Stop arguing about code style. In this course you get a production-proven setup with analyzers, CI quality gates, and architecture tests â the exact system I use in real projects. Join here.
Not sure yet? Grab the free Starter Kit â a drop-in setup with the essentials from Module 01.
Design Patterns that Deliver â Solve real problems with 5 battle-tested patterns (Builder, Decorator, Strategy, Adapter, Mediator) using practical, real-world examples. Trusted by 650+ developers.
Just getting started? Design Patterns Simplified covers 10 essential patterns in a beginner-friendly, 30-page guide for just $9.95.
Every Monday morning, I share 1 actionable tip on C#, .NET & Architecture that you can use right away. Join here.
Join 20,000+ subscribers who mass-improve their .NET skills with actionable tips on C#, Software Architecture & Best Practices.
Subscribe to the TheCodeMan.net and be among the 20,000+ subscribers gaining practical tips and resources to enhance your .NET expertise.