# Using MassTransit with RabbitMQ and Azure Service Bus

> MassTransit is an open-source distributed application framework for .NET. It provides a messaging abstraction on top of the supported message transports. In this week's issue, I'll show you how to use MassTransit.

Published: 2024-01-06. Author: Milan Jovanović.

Canonical: https://milanjovanovic.tech/blog/using-masstransit-with-rabbitmq-and-azure-service-bus

MassTransit gives you one messaging abstraction over several transports, so the same publish and consume code runs on RabbitMQ or Azure Service Bus.
You install the matching transport package, call `AddMassTransit`, and select the transport with `UsingRabbitMq` or `UsingAzureServiceBus`.
MassTransit configures the broker topology for you.

[MassTransit](https://masstransit.io/) is an open-source distributed application framework for .NET.
It provides a messaging abstraction on top of the supported message transports.
MassTransit lets you focus on adding business value instead of worrying about messaging complexity.

MassTransit supports many message transport technologies.
Here are a few that are popular:

- RabbitMQ
- Azure Service Bus
- Amazon SQS
- Kafka

In today's newsletter, I'll show you how to install and configure MassTransit in .NET.
We'll connect MassTransit to a few message brokers - RabbitMQ and Azure Service Bus.
And we will also cover how to publish and consume messages with MassTransit.

## Why Use MassTransit?

MassTransit solves many challenges of building distributed applications.
You (almost) don't have to think about the underlying message transport.
This allows you to focus on providing business value.

Here are a few things MassTransit does for you:

- **Message routing** - Type-based publish/subscribe, automatic broker topology configuration
- **Exception handling** - Messages can be retried or moved to an error queue
- **Dependency injection** - Service collection configuration and scope service provider
- **Request-Response** - Handle requests with automatic response routing
- **Observability** - Native [Open Telemetry (OTEL)](https://opentelemetry.io/) support
- **Scheduling** - Schedule message delivery using transport delay, Quartz.NET, or Hangfire
- [**Sagas**](https://milanjovanovic.tech/blog/saga-pattern-dotnet) - Reliable, durable, event-driven workflow orchestration

Let's see how to start using MassTransit.

## Installing and Configuring MassTransit with RabbitMQ

You need to install the `MassTransit` library.
If you already have a message transport, you can install the respective transport library.
Let's add the `MassTransit.RabbitMQ` library to configure [RabbitMQ](https://www.rabbitmq.com/) as the transport mechanism.

```powershell
Install-Package MassTransit

Install-Package MassTransit.RabbitMQ
```

Then, you can configure the required services for `MassTransit`.
The `AddMassTransit` method accepts a delegate where you can configure many settings.
For example, you can set the messaging endpoints to use kebab case naming by calling `SetKebabCaseEndpointNameFormatter`.
This is also where you configure the transport mechanism.
Calling `UsingRabbitMq` allows you to connect RabbitMQ as the transport mechanism.

```csharp
builder.Services.AddMassTransit(busConfigurator =>
{
    busConfigurator.SetKebabCaseEndpointNameFormatter();

    busConfigurator.UsingRabbitMq((context, configurator) =>
    {
        configurator.Host("localhost", "/", h =>
        {
            h.Username("guest");
            h.Password("guest");
        });

        configurator.ConfigureEndpoints(context);
    });
});
```

MassTransit takes care of setting up the required broker topology.
RabbitMQ supports exchanges and queues, so messages are sent or published to exchanges.
RabbitMQ routes those messages through exchanges to the appropriate queues.

You can start RabbitMQ locally inside a Docker container:

```csharp
docker run -d --name rabbitmq -p 5672:5672
```

## Configuring MassTransit with Azure Service Bus

[Azure Service Bus](https://azure.microsoft.com/en-us/products/service-bus)
is a cloud-based message broker with support for queues and topics.
MassTransit fully supports Azure Service Bus, including many advanced features and capabilities.
However, you must be on the Standard or Premium tier of the Microsoft Azure Service Bus service.

To configure MassTransit to work with Azure Service Bus, you need to install the required transport library:

```powershell
Install-Package MassTransit.Azure.ServiceBus.Core
```

Then, you can connect to Azure Service Bus by calling `UsingAzureServiceBus` and providing the connection string.
Everything else remains the same.
MassTransit takes care of configuring the broker topology.
MassTransit sends messages to topics, and Azure Service Bus routes those messages to the appropriate queues.

```csharp
builder.Services.AddMassTransit(busConfigurator =>
{
    busConfigurator.SetKebabCaseEndpointNameFormatter();

    busConfigurator.UsingAzureServiceBus((context, configurator) =>
    {
        configurator.Host("<CONNECTION_STRING>");

        configurator.ConfigureEndpoints(context);
    });
});
```

## Using the MassTransit In Memory Transport

You can also configure MassTransit to use an in-memory transport.
It's useful for testing, because it doesn't require a message broker to be running.
Another advantage is that it's fast.

However, there's a big problem with the in-memory transport - **it's not durable.**

If the message bus is stopped, all messages are lost.
Don't use the in-memory transport for production systems.

It will only work on a single machine.
So, it doesn't make sense for distributed applications.

```csharp
builder.Services.AddMassTransit(busConfigurator =>
{
    busConfigurator.SetKebabCaseEndpointNameFormatter();

    busConfigurator.UsingInMemory((context, configurator) =>
    {
        configurator.ConfigureEndpoints(context);
    });
});
```

## Message Types

MassTransit requires message types to be [reference types.](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/reference-types)
So, you can use a `class`, `record` or `interface` to define a message.

You'll often create two types of messages: commands and events.

A command is an instruction to perform some action.
Commands are intended to have exactly one consumer.
Commands are expressed using verbs first: `CreateArticle`, `PublishArticle`, `ShareArticle`.

An event represents that something of significance happened.
Events can have one or many consumers.
Events should have a name in the past tense: `ArticleCreated`, `ArticlePublished`, `ArticleShared`.

Here's an example `ArticleCreated` message containing information about an article:

```csharp
public record ArticleCreated
{
    public Guid Id { get; init; }
    public string Title { get; init; }
    public string Content { get; init; }
    public DateTime CreatedOnUtc { get; init; }
}
```

Using `public set` or `public init` properties is recommended to avoid serialization problems with `System.Text.Json`.

## Publishing and Consuming Messages

You can use the `IPublishEndpoint` service to publish messages with MassTransit.
The framework routes the message to the appropriate queue or topic based on the message type.

```csharp {3,5}
app.MapPost("article", async (
    CreateArticleRequest request,
    IPublishEndpoint publishEndpoint) =>
{
    await publishEndpoint.Publish(new ArticleCreated
    {
        Id = Guid.NewGuid(),
        Title = request.Title,
        Content = request.Content,
        CreatedOnUtc = DateTime.UtcNow
    });

    return Results.Accepted();
});
```

To consume an `ArticleCreated` message, you need to implement the `IConsumer` interface.
The `IConsumer` has one `Consume` method where you place your business logic.
The consumer also gives you access to the `ConsumeContext`, which you can use to send further messages.

```csharp
public class ArticleCreatedConsumer(ApplicationDbContext dbContext)
    : IConsumer<ArticleCreatedEvent>
{
    public async Task Consume(ConsumeContext<ArticleCreatedEvent> context)
    {
        ArticleCreated message = context.Message;

        var article = new Article
        {
            Id = message.Id,
            Title = message.Title,
            Content = message.Content,
            CreatedOnUtc = message.CreatedOnUtc
        };

        dbContext.Add(article);

        await dbContext.SaveChangesAsync();
    }
}
```

MassTransit doesn't automatically know that the `ArticleCreatedConsumer` exists.
You have to configure the consumer when calling `AddMassTransit`.
The `AddConsumer` method registers the consumer type with the bus.

```csharp {5}
builder.Services.AddMassTransit(busConfigurator =>
{
    busConfigurator.SetKebabCaseEndpointNameFormatter();

    busConfigurator.AddConsumer<ArticleCreatedConsumer>();

    // ...
});
```

## Next Steps

**MassTransit** is an excellent messaging library I often use when building distributed applications.
The setup is straightforward, and there are only a few important abstractions.
You need to know abstraction for publishing messages (`IPublishEndpoint`) and consuming messages (`IConsumer`).
MassTransit takes care of doing the heavy lifting for you.

If you aren't already using it, I highly recommend adding MassTransit to your toolbox.

Here are some more practical **MassTransit learning resources**:

- [Request-Response pattern with MassTransit](https://youtu.be/NjsoykEOkrk)
- [RabbitMQ and MassTransit tutorial](https://youtu.be/CTKWFMZVIWA)
- [Microservices with RabbitMQ](https://youtu.be/MzC0PgYocmk)
- [Saga pattern with RabbitMQ](https://milanjovanovic.tech/blog/implementing-the-saga-pattern-with-rebus-and-rabbitmq)
- [Orchestration vs Choreography](https://milanjovanovic.tech/blog/orchestration-vs-choreography)
- [Messaging with Azure Service Bus](https://milanjovanovic.tech/blog/messaging-made-easy-with-azure-service-bus)

That's all for today.

See you next week.

---

## Frequently asked questions

### What is MassTransit?

MassTransit is an open-source distributed application framework for .NET. It provides a messaging abstraction on top of supported message transports such as RabbitMQ, Azure Service Bus, Amazon SQS, and Kafka, handling message routing, retries, dependency injection, sagas, and observability for you.

### How do you configure MassTransit with RabbitMQ?

Install the MassTransit and MassTransit.RabbitMQ packages, then call AddMassTransit and configure the transport with UsingRabbitMq, setting the host and credentials and calling ConfigureEndpoints. MassTransit sets up the required broker topology of exchanges and queues automatically.

### Does MassTransit support Azure Service Bus?

Yes. Install the MassTransit.Azure.ServiceBus.Core package and call UsingAzureServiceBus with your connection string. You must be on the Standard or Premium tier of Azure Service Bus. MassTransit sends messages to topics and Azure Service Bus routes them to the appropriate queues.

### When should you use the MassTransit in-memory transport?

Only for testing. It's fast and doesn't require a running message broker, but it isn't durable: if the message bus stops, all messages are lost. It also only works on a single machine, so never use it for production or distributed systems.

### What is the difference between a command and an event in messaging?

A command is an instruction to perform an action, has exactly one consumer, and is named verb-first, like CreateArticle. An event represents something significant that happened, can have one or many consumers, and is named in the past tense, like ArticleCreated.

### How do you publish and consume messages with MassTransit?

Publish with the IPublishEndpoint service, which routes messages by their type. Consume by implementing IConsumer with a Consume method containing your business logic, then register the consumer with AddConsumer inside the AddMassTransit configuration.
