Commify.Titan.API.RabbitMQ
0.13.0
See the version list below for details.
dotnet add package Commify.Titan.API.RabbitMQ --version 0.13.0
NuGet\Install-Package Commify.Titan.API.RabbitMQ -Version 0.13.0
<PackageReference Include="Commify.Titan.API.RabbitMQ" Version="0.13.0" />
<PackageVersion Include="Commify.Titan.API.RabbitMQ" Version="0.13.0" />
<PackageReference Include="Commify.Titan.API.RabbitMQ" />
paket add Commify.Titan.API.RabbitMQ --version 0.13.0
#r "nuget: Commify.Titan.API.RabbitMQ, 0.13.0"
#:package Commify.Titan.API.RabbitMQ@0.13.0
#addin nuget:?package=Commify.Titan.API.RabbitMQ&version=0.13.0
#tool nuget:?package=Commify.Titan.API.RabbitMQ&version=0.13.0
Commify.Titan.API.RabbitMQ
Self-contained NuGet package that adds RabbitMQ messaging to any .NET 10 application. Supports event publishing/consuming with zero configuration, custom message routing, outbox pattern with PostgreSQL, and dead letter queues.
Contact: Titan API Team
Configuration
Add the following to appsettings.json:
{
"TitanCommunication": {
"RabbitMQ": {
"Host": "host",
"Port": 5672,
"BasicCredentials": {
"Username": "username",
"Password": "password"
}
}
}
}
- BasicCredentials enables basic authentication. When omitted, the package falls back to AAD token authentication.
Environment variables
| Variable | Required | Description |
|---|---|---|
K8S_POD_NAME |
Yes | Used to generate unique, auto-deleting queue names for consumers that don't specify a QueueName. |
Initialization
Register the Titan framework, then initialize RabbitMQ connections at startup:
var builder = Host.CreateApplicationBuilder(args);
builder.Services
.AddTitanFramework(builder.Configuration);
// Register publishers and consumers (see sections below)
var app = builder.Build();
await app.InitializeAsync(); // opens RabbitMQ connections
await app.ApplyEventPublisherMigrations(); // applies outbox EF Core migrations (only if using outbox)
await app.RunAsync();
Publishing
Event publishing
RegisterEventPublisher uses the shared event defaults (RabbitMqEventDefaults) and the outbox pattern. No manual settings required.
services.RegisterEventPublisher<LoginEventData>(
context.Configuration,
context.Configuration.GetConnectionString("AppDb")!);
Inject IOutboxMessagePublisher<T> and call SaveChangesAsync to transactionally save the message alongside your domain changes:
public class LoginService(
IOutboxMessagePublisher<LoginEventData> publisher,
IDbContextFactory<AppDbContext> dbContextFactory)
{
public async Task HandleLoginAsync(LoginEventData data, CancellationToken ct)
{
var dbContext = await dbContextFactory.CreateDbContextAsync(ct);
QueueMessage<LoginEventData> message = new()
{
Id = Guid.NewGuid(),
Headers = new QueueHeaders
{
CorrelationId = Guid.NewGuid(),
Source = "LoginService",
Type = "LoginEventData",
OccurredAt = DateTimeOffset.UtcNow
},
Payload = data
};
await publisher.SaveChangesAsync(dbContext, message, ct);
}
}
A background service polls the outbox and publishes pending messages with exponential backoff.
Message publishing
RegisterMessagePublisher registers an IMessagePublisher<T> with custom exchange settings. Available in two overloads:
// Without IServiceProvider
services.RegisterMessagePublisher<Message>(context.Configuration, ()
=> new()
{
VirtualHost = "API",
ExchangeName = "ex.mock",
ExchangeType = "fanout"
});
// With IServiceProvider
services.RegisterMessagePublisher<Message>(context.Configuration, (sp)
=> new()
{
VirtualHost = "API",
ExchangeName = "ex.mock",
ExchangeType = "fanout"
});
Inject IMessagePublisher<T> and call PublishAsync:
await messagePublisher.PublishAsync(queueMessage, customTrace, cancellationToken);
Outbox message publishing
RegisterMessagePublisherWithOutbox combines custom exchange settings with the PostgreSQL outbox:
// Without IServiceProvider
services.RegisterMessagePublisherWithOutbox<Message>(
context.Configuration,
dbConnectionString,
() => new()
{
VirtualHost = "API",
ExchangeName = "ex.custom",
ExchangeType = "direct",
RoutingKey = "my.routing.key"
});
// With IServiceProvider
services.RegisterMessagePublisherWithOutbox<Message>(
context.Configuration,
dbConnectionString,
(sp) => new()
{
VirtualHost = "API",
ExchangeName = "ex.custom",
ExchangeType = "direct",
RoutingKey = "my.routing.key"
});
Inject IOutboxMessagePublisher<T> and use SaveChangesAsync.
Consuming
Event consuming
RegisterEventConsumer uses the shared event defaults (RabbitMqEventDefaults). No manual settings required.
services.RegisterEventConsumer<LoginEventData, LoginEventHandler>(context.Configuration);
Implement IMessageConsumer<T>:
public class LoginEventHandler : IMessageConsumer<LoginEventData>
{
public async Task HandleMessageAsync(
QueueMessage<LoginEventData> message,
RabbitMQConsumerTrace customTrace,
CancellationToken cancellationToken)
{
// Process the message
}
public async Task HandleExceptionAsync(
Exception exception,
RabbitMQConsumerTrace customTrace,
CancellationToken cancellationToken)
{
// Handle consumer errors
}
}
Message consuming
RegisterMessageConsumer requires custom settings. Available in two overloads:
// Without IServiceProvider
services.RegisterMessageConsumer<LoginEventData, LoginEventHandler>(context.Configuration, ()
=> new()
{
VirtualHost = "API",
ExchangeNameToBind = "ex.events",
ExchangeType = "fanout",
QueueName = "q.my-service.login-events", // optional, auto-generated from K8S_POD_NAME if omitted
RoutingKey = "login.#" // optional
});
// With IServiceProvider
services.RegisterMessageConsumer<LoginEventData, LoginEventHandler>(context.Configuration, (sp)
=> new()
{
VirtualHost = "API",
ExchangeNameToBind = "ex.events",
ExchangeType = "fanout"
});
When QueueName is omitted, a queue is auto-created using K8S_POD_NAME and deleted when the application stops.
Dead letter queues
Failed messages can be routed to a dead letter queue by setting three properties on RabbitMqConsumerSettings:
| Setting | Description |
|---|---|
DeadLetterQueueName |
Queue where failed messages are stored |
DeadLetterExchangeName |
Exchange that routes to the dead letter queue |
DeadLetterRoutingKey |
Routing key for dead letter message routing |
All three must be set, or none. Partial configuration throws an ArgumentNullException at startup.
services.RegisterMessageConsumer<LoginEventData, LoginEventHandler>(context.Configuration, ()
=> new()
{
VirtualHost = "API",
ExchangeNameToBind = "ex.events",
ExchangeType = "fanout",
DeadLetterQueueName = "q.dlx.login-events",
DeadLetterExchangeName = "ex.dlx.events",
DeadLetterRoutingKey = "dlx.login-events"
});
When configured, any unhandled exception in HandleMessageAsync causes the message to be published to the dead letter exchange with the original headers plus a DeadLetterReason header containing the exception message. Dead letter exchanges always use the topic exchange type.
Custom implementation
For full control over publishing and consuming, use RegisterRabbitMQMessaging to register only the connection management layer:
services.RegisterRabbitMQMessaging(context.Configuration);
This registers a singleton IConnectionManagement that you can inject to create channels directly:
var channel = await connectionManagement.CreateChannelAsync("API", customTrace, cancellationToken);
Key types
| Type | Description |
|---|---|
QueueMessage<T> |
Message envelope containing Id, Headers, and Payload |
QueueHeaders |
Message metadata: CorrelationId, Source, Type, OccurredAt, TestScenario, DeadLetterReason |
IMessagePublisher<T> |
Publishes messages directly to RabbitMQ |
IOutboxMessagePublisher<T> |
Saves messages to a PostgreSQL outbox for reliable delivery |
IMessageConsumer<T> |
Consumer contract with HandleMessageAsync and HandleExceptionAsync |
IDeadLetterPublisher<T> |
Publishes failed messages to a dead letter exchange |
IConnectionManagement |
Low-level channel creation per virtual host |
RabbitMqPublisherSettings |
Publisher config: VirtualHost, ExchangeName, ExchangeType, RoutingKey |
RabbitMqConsumerSettings |
Consumer config: VirtualHost, ExchangeNameToBind, ExchangeType, QueueName, RoutingKey, dead letter settings |
RabbitMqEventDefaults |
Shared constants for event routing: ExchangeName, ExchangeType, VirtualHost |
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Commify.Titan.API.Framework (>= 1.3.2)
- Microsoft.Extensions.Configuration.UserSecrets (>= 10.0.3)
- Npgsql.EntityFrameworkCore.PostgreSQL (>= 10.0.0)
- RabbitMQ.Client (>= 7.2.1)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.0.6 | 67 | 3/10/2026 |
| 1.0.5 | 95 | 3/9/2026 |
| 1.0.4 | 75 | 3/8/2026 |
| 1.0.3 | 71 | 3/7/2026 |
| 1.0.2 | 71 | 3/7/2026 |
| 1.0.1 | 71 | 3/6/2026 |
| 1.0.0 | 66 | 3/6/2026 |
| 0.16.0 | 69 | 3/6/2026 |
| 0.15.0 | 69 | 3/6/2026 |
| 0.14.0 | 72 | 3/5/2026 |
| 0.13.0 | 67 | 3/5/2026 |
| 0.8.0 | 68 | 3/5/2026 |
| 0.7.0 | 68 | 3/5/2026 |
| 0.6.0 | 88 | 3/2/2026 |
| 0.5.0 | 87 | 2/24/2026 |
| 0.1.0 | 110 | 2/20/2026 |