RabbitMQ C# Cheat-Sheet

June 8, 20254 min read

RabbitMQ C# Cheat-Sheet

RabbitMQ Docker setup

Run RabbitMQ with the management plugin enabled:

docker run -d \
  --name rabbitmq \
  -p 5672:5672 \
  -p 15672:15672 \
  rabbitmq:management

The connection string is amqp://localhost:5672

You can connect to your instance using RabbitGUI at http://localhost:15672 (guest/guest)

Rabbitgui connexion screen

Docker compose setup for RabbitMQ

Create a docker-compose.yml file with custom credentials and persistent storage:

version: '3'
services:
  rabbitmq:
    image: rabbitmq:management
    container_name: rabbitmq
    ports:
      - "5672:5672"
      - "15672:15672"
    environment:
      RABBITMQ_DEFAULT_USER: user
      RABBITMQ_DEFAULT_PASS: password
    volumes:
      - rabbitmq_data:/var/lib/rabbitmq
 
volumes:
  rabbitmq_data:

The connection string is amqp://user:password@localhost:5672

You can connect to your instance using RabbitGUI at http://localhost:15672 (user/password)

Installation in C#

.NET CLI

Add the RabbitMQ.Client NuGet package to your project:

dotnet add package RabbitMQ.Client

Package Manager Console

Install-Package RabbitMQ.Client

Producer example

You can publish directly to a queue using the BasicPublishAsync method:

using RabbitMQ.Client;
using System.Text;
 
var factory = new ConnectionFactory { HostName = "localhost" };
 
using var connection = await factory.CreateConnectionAsync();
using var channel = await connection.CreateChannelAsync();
 
await channel.QueueDeclareAsync(queue: "my_queue", durable: false,
    exclusive: false, autoDelete: false, arguments: null);
 
var body = Encoding.UTF8.GetBytes("Hello RabbitGUI!");
await channel.BasicPublishAsync(exchange: "", routingKey: "my_queue", body: body);

Consumer example

Your consumer can listen to messages from a queue using the BasicConsumeAsync method:

using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System.Text;
 
var factory = new ConnectionFactory { HostName = "localhost" };
 
using var connection = await factory.CreateConnectionAsync();
using var channel = await connection.CreateChannelAsync();
 
await channel.QueueDeclareAsync(queue: "my_queue", durable: false,
    exclusive: false, autoDelete: false, arguments: null);
 
var consumer = new AsyncEventingBasicConsumer(channel);
consumer.ReceivedAsync += async (model, ea) =>
{
    var message = Encoding.UTF8.GetString(ea.Body.ToArray());
    Console.WriteLine($"Message: {message}");
};
 
await channel.BasicConsumeAsync(queue: "my_queue", autoAck: true, consumer: consumer);
 
Console.ReadLine();

Exchanges examples

Direct

A direct exchange routes messages to queues based on exact routing key matches:

using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System.Text;
 
var factory = new ConnectionFactory { HostName = "localhost" };
 
using var connection = await factory.CreateConnectionAsync();
using var channel = await connection.CreateChannelAsync();
 
await channel.ExchangeDeclareAsync(exchange: "my_exchange", type: "direct");
await channel.QueueDeclareAsync(queue: "my_queue", durable: false,
    exclusive: false, autoDelete: false, arguments: null);
await channel.QueueBindAsync(queue: "my_queue", exchange: "my_exchange",
    routingKey: "my.routing.key");
 
var body = Encoding.UTF8.GetBytes("Hello RabbitGUI!");
await channel.BasicPublishAsync(exchange: "my_exchange",
    routingKey: "my.routing.key", body: body);
 
var consumer = new AsyncEventingBasicConsumer(channel);
consumer.ReceivedAsync += async (model, ea) =>
{
    var message = Encoding.UTF8.GetString(ea.Body.ToArray());
    Console.WriteLine($"Message: {message}");
};
 
await channel.BasicConsumeAsync(queue: "my_queue", autoAck: true, consumer: consumer);

Fanout

A fanout exchange broadcasts messages to all bound queues, ignoring routing keys:

using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System.Text;
 
var factory = new ConnectionFactory { HostName = "localhost" };
 
using var connection = await factory.CreateConnectionAsync();
using var channel = await connection.CreateChannelAsync();
 
await channel.ExchangeDeclareAsync(exchange: "my_exchange", type: "fanout");
await channel.QueueDeclareAsync(queue: "my_queue", durable: false,
    exclusive: false, autoDelete: false, arguments: null);
await channel.QueueBindAsync(queue: "my_queue", exchange: "my_exchange",
    routingKey: "");
 
var body = Encoding.UTF8.GetBytes("Hello RabbitGUI!");
await channel.BasicPublishAsync(exchange: "my_exchange", routingKey: "", body: body);
 
var consumer = new AsyncEventingBasicConsumer(channel);
consumer.ReceivedAsync += async (model, ea) =>
{
    var message = Encoding.UTF8.GetString(ea.Body.ToArray());
    Console.WriteLine($"Message: {message}");
};
 
await channel.BasicConsumeAsync(queue: "my_queue", autoAck: true, consumer: consumer);

Topic

A topic exchange routes messages based on wildcard pattern matching (* for one word, # for zero or more words):

using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System.Text;
 
var factory = new ConnectionFactory { HostName = "localhost" };
 
using var connection = await factory.CreateConnectionAsync();
using var channel = await connection.CreateChannelAsync();
 
await channel.ExchangeDeclareAsync(exchange: "my_exchange", type: "topic");
await channel.QueueDeclareAsync(queue: "my_queue", durable: false,
    exclusive: false, autoDelete: false, arguments: null);
await channel.QueueBindAsync(queue: "my_queue", exchange: "my_exchange",
    routingKey: "*.routing.*");
 
var body = Encoding.UTF8.GetBytes("Hello RabbitGUI!");
await channel.BasicPublishAsync(exchange: "my_exchange",
    routingKey: "my.routing.key", body: body);
 
var consumer = new AsyncEventingBasicConsumer(channel);
consumer.ReceivedAsync += async (model, ea) =>
{
    var message = Encoding.UTF8.GetString(ea.Body.ToArray());
    Console.WriteLine($"Message: {message}");
};
 
await channel.BasicConsumeAsync(queue: "my_queue", autoAck: true, consumer: consumer);

Message acknowledgements

Automatic acknowledgement

RabbitMQ will dequeue messages as soon as they've been sent down the wire.

await channel.BasicConsumeAsync(queue: "my_queue", autoAck: true, consumer: consumer);

Manual acknowledgement

Manually acknowledge messages after processing to ensure they are removed from the queue:

var consumer = new AsyncEventingBasicConsumer(channel);
consumer.ReceivedAsync += async (model, ea) =>
{
    // Process message...
    await channel.BasicAckAsync(deliveryTag: ea.DeliveryTag, multiple: false);
};
 
await channel.BasicConsumeAsync(queue: "my_queue", autoAck: false, consumer: consumer);

Reject and requeue

Reject a message and put it back in the queue for reprocessing:

var consumer = new AsyncEventingBasicConsumer(channel);
consumer.ReceivedAsync += async (model, ea) =>
{
    // Process message...
    await channel.BasicNackAsync(deliveryTag: ea.DeliveryTag,
        multiple: false, requeue: true);
};
 
await channel.BasicConsumeAsync(queue: "my_queue", autoAck: false, consumer: consumer);

Reject and do not requeue

Reject a message and discard it (sends to dead letter queue if configured):

var consumer = new AsyncEventingBasicConsumer(channel);
consumer.ReceivedAsync += async (model, ea) =>
{
    // Process message...
    await channel.BasicNackAsync(deliveryTag: ea.DeliveryTag,
        multiple: false, requeue: false);
};
 
await channel.BasicConsumeAsync(queue: "my_queue", autoAck: false, consumer: consumer);

Dead Letter Queues

Configure a queue with a dead letter exchange to catch rejected or expired messages:

using RabbitMQ.Client;
 
var factory = new ConnectionFactory { HostName = "localhost" };
 
using var connection = await factory.CreateConnectionAsync();
using var channel = await connection.CreateChannelAsync();
 
// Create the dead letter exchange and queue
await channel.ExchangeDeclareAsync(exchange: "dlx_exchange", type: "direct");
await channel.QueueDeclareAsync(queue: "dead_letter_queue", durable: false,
    exclusive: false, autoDelete: false, arguments: null);
await channel.QueueBindAsync(queue: "dead_letter_queue",
    exchange: "dlx_exchange", routingKey: "");
 
// Create main queue with dead letter configuration
var args = new Dictionary<string, object?>
{
    { "x-dead-letter-exchange", "dlx_exchange" },
    { "x-dead-letter-routing-key", "" }
};
 
await channel.QueueDeclareAsync(queue: "my_queue", durable: false,
    exclusive: false, autoDelete: false, arguments: args);

More articles about RabbitMQ

How to manually publish messages to RabbitMQHow to manually publish messages to RabbitMQSometimes you just need to test something quickly, you want to trigger a specific job, or you want to retry a task that failedRabbitMQ: maximum size of a messageRabbitMQ: maximum size of a messageThe maximum size of a message in RabbitMQ is not defined by the protocol, but by the implementation. Unfortunately, this value is not well documented and has changed a lot over timeHow to visually explore RabbitMQ queue bindingsHow to visually explore RabbitMQ queue bindingsThere are many ways messages can be routed to queues in RabbitMQ, and it can be hard to understand how they are connected in a single place

RabbitGUI, the missing RabbitMQ IDE

Debug, monitor, and manage RabbitMQ with a modern developer interface.

Try nowRabbitGUI screenshot