Oragon.RabbitMQ
1.8.0
Prefix Reserved
dotnet add package Oragon.RabbitMQ --version 1.8.0
NuGet\Install-Package Oragon.RabbitMQ -Version 1.8.0
<PackageReference Include="Oragon.RabbitMQ" Version="1.8.0" />
<PackageVersion Include="Oragon.RabbitMQ" Version="1.8.0" />
<PackageReference Include="Oragon.RabbitMQ" />
paket add Oragon.RabbitMQ --version 1.8.0
#r "nuget: Oragon.RabbitMQ, 1.8.0"
#:package Oragon.RabbitMQ@1.8.0
#addin nuget:?package=Oragon.RabbitMQ&version=1.8.0
#tool nuget:?package=Oragon.RabbitMQ&version=1.8.0

Oragon.RabbitMQ
Minimal APIs for RabbitMQ in .NET — Consume queues with the same MapQueue() pattern you already know from MapPost().
Oragon.RabbitMQ is not HTTP/Kestrel-based. It is a fully custom implementation built on RabbitMQ.Client 7.x natively.
Quality
Releases
Project
What is Oragon.RabbitMQ?
If you know ASP.NET Core Minimal APIs, you already know Oragon.RabbitMQ:
// ASP.NET Core — HTTP
app.MapPost("/orders", ([FromServices] OrderService svc, [FromBody] OrderCreated msg) => svc.HandleAsync(msg));
// Oragon.RabbitMQ — AMQP
app.MapQueue("orders", ([FromServices] OrderService svc, [FromBody] OrderCreated msg) => svc.HandleAsync(msg));
It provides everything you need to create resilient RabbitMQ consumers without the need to study numerous books and articles or introduce unknown risks to your environment. All queue consumption settings are configurable through a friendly, fluent, and consistent API.
Why Oragon.RabbitMQ?
- Minimal API design — familiar
MapQueue()pattern, zero learning curve for ASP.NET Core developers - RabbitMQ.Client 7.x native — no HTTP, no Kestrel, pure AMQP
- Near-zero overhead — benchmarks prove 0-1% overhead for I/O-bound workloads
- Built-in resilience — automatic Ack/Nack/Reject with manual acknowledgment by default
- DI-first —
[FromServices],[FromBody],[FromAmqpHeader]attribute binding - Pluggable serialization — System.Text.Json or Newtonsoft.Json out of the box
- Composable flow control — Ack, Nack, Reject, Reply, Forward, and Compose results
- .NET Aspire integration — first-class support via
Oragon.RabbitMQ.AspireClient - OpenTelemetry native — via RabbitMQ.Client 7.x built-in instrumentation
- Multi-framework — targets .NET 9 and 10
Quick Start
Standalone
dotnet add package Oragon.RabbitMQ
dotnet add package Oragon.RabbitMQ.Serializer.SystemTextJson
using Oragon.RabbitMQ;
using Oragon.RabbitMQ.Serializer;
using RabbitMQ.Client;
var builder = Host.CreateApplicationBuilder(args);
// 1. Register consumer infrastructure
builder.AddRabbitMQConsumer();
// 2. Register serializer
builder.Services.AddAmqpSerializer(options: JsonSerializerOptions.Default);
// 3. Register RabbitMQ connection
builder.Services.AddSingleton<IConnectionFactory>(sp => new ConnectionFactory()
{
Uri = new Uri("amqp://guest:guest@localhost:5672"),
DispatchConsumersAsync = true
});
builder.Services.AddSingleton(sp =>
sp.GetRequiredService<IConnectionFactory>().CreateConnectionAsync().GetAwaiter().GetResult());
// 4. Register your service
builder.Services.AddSingleton<OrderService>(); // singleton, scoped or transient
var app = builder.Build();
Example 1
// 5. Map queue to handler
app.MapQueue("orders", ([FromServices] OrderService svc, OrderCreated msg) =>
svc.HandleAsync(msg));
app.Run();
Example 2
Assume the service has a method CanProcess that returns a boolean.
app.MapQueue("orders", async ([FromServices] OrderService svc, OrderCreated msg) =>
{
if (svc.CanProcess(msg))
{
await svc.HandleAsync(msg);
return AmqpResults.Ack();
}
return AmqpResults.Nack(requeue: true);
});
Example 3
You can also handle exceptions yourself and return a valid IAmqpResult:
app.MapQueue("orders", async ([FromServices] OrderService svc, OrderCreated msg) =>
{
try
{
await svc.HandleAsync(msg);
return AmqpResults.Ack();
}
catch (Exception ex)
{
// Log the exception
return AmqpResults.Nack(requeue: true);
}
});
With .NET Aspire
Replace Aspire.RabbitMQ.Client with Oragon.RabbitMQ.AspireClient to get RabbitMQ.Client 7.x support and a built-in RabbitMQ health check without the AspNetCore.HealthChecks.Rabbitmq dependency:
dotnet add package Oragon.RabbitMQ.AspireClient
builder.AddRabbitMQClient("rabbitmq");
After
Aspire.RabbitMQ.Clientgains RabbitMQ.Client 7.x support, theOragon.RabbitMQ.AspireClientpackage will be deprecated.
Packages
| Package | Purpose |
|---|---|
Oragon.RabbitMQ |
Core library — consumer infrastructure, MapQueue, flow control |
Oragon.RabbitMQ.Abstractions |
Interfaces (IAmqpResult, IAmqpSerializer, IAmqpContext) |
Oragon.RabbitMQ.Serializer.SystemTextJson |
System.Text.Json serializer |
Oragon.RabbitMQ.Serializer.NewtonsoftJson |
Newtonsoft.Json serializer |
Oragon.RabbitMQ.AspireClient |
.NET Aspire integration (RabbitMQ.Client 7.x) |
Configuration Reference
All configuration is done through fluent methods on the ConsumerDescriptor returned by MapQueue():
| Method | Description | Default |
|---|---|---|
.WithPrefetch(ushort) |
Number of messages prefetched from the broker | 1 |
.WithDispatchConcurrency(ushort) |
Concurrent message processing slots | 1 |
.WithConsumerTag(string) |
Custom consumer tag | auto-generated |
.WithExclusive(bool) |
Exclusive consumer on the queue | false |
.WithTopology(Func<IChannel, CancellationToken, Task>) |
Declare exchanges/queues/bindings on startup | none |
.WithConnection(Func<IServiceProvider, CancellationToken, Task<IConnection>>) |
Custom connection factory | IConnection from DI |
.WithSerializer(Func<IServiceProvider, IAmqpSerializer>) |
Custom serializer factory | IAmqpSerializer from DI |
.WithChannel(Func<IConnection, CancellationToken, Task<IChannel>>) |
Custom channel factory | auto-created |
.WhenSerializationFail(Func<IAmqpContext, Exception, IAmqpResult>) |
Behavior on deserialization errors | Reject(requeue: false) |
.WhenProcessFail(Func<IAmqpContext, Exception, IAmqpResult>) |
Behavior on handler exceptions | Nack(requeue: false) |
app.MapQueue("orders", ([FromServices] OrderService svc, OrderCreated msg) =>
svc.HandleAsync(msg))
.WithPrefetch(100)
.WithDispatchConcurrency(8)
.WhenProcessFail((ctx, ex) => AmqpResults.Nack(requeue: true));
Flow Control
By default, Oragon handles acknowledgments automatically:
- Success →
BasicAck - Serialization failure →
BasicReject(no requeue) — use dead-lettering - Processing failure →
BasicNack(no requeue) — use dead-lettering
For explicit control, return an IAmqpResult from your handler:
| Group | Method | Description |
|---|---|---|
| Basic | AmqpResults.Ack() |
Acknowledge the message |
AmqpResults.Nack(requeue) |
Negative acknowledge | |
AmqpResults.Reject(requeue) |
Reject the message | |
| RPC | AmqpResults.Reply<T>(T) |
Reply to the caller |
AmqpResults.ReplyAndAck<T>(T) |
Reply and acknowledge | |
| Routing | AmqpResults.Forward<T>(exchange, routingKey, mandatory, params T[]) |
Forward to another exchange |
AmqpResults.ForwardAndAck<T>(exchange, routingKey, mandatory, params T[]) |
Forward and acknowledge | |
| Composition | AmqpResults.Compose(params IAmqpResult[]) |
Combine multiple results |
Model Binding
Attributes
| Attribute | Resolves from |
|---|---|
[FromServices] |
DI container (supports keyed services) |
[FromBody] |
Deserialized message body |
[FromAmqpHeader("key")] |
AMQP message header by key |
Auto-bound Types
These types are resolved automatically by the model binder without any attribute:
| Type | Value |
|---|---|
IConnection |
Current RabbitMQ connection |
IChannel |
Current RabbitMQ channel |
BasicDeliverEventArgs |
Raw delivery event |
DeliveryModes |
Message delivery mode |
IReadOnlyBasicProperties |
Message properties |
IServiceProvider |
Scoped service provider |
IAmqpContext |
Full AMQP context |
CancellationToken |
Cancellation token |
Auto-bound String Parameters
String parameters are matched by name convention:
| Parameter names | Value |
|---|---|
queue, queueName |
Name of the consumed queue |
routing, routingKey |
Message routing key |
exchange, exchangeName |
Source exchange name |
consumer, consumerTag |
Consumer tag |
Telemetry
RabbitMQ.Client 7.x implements native OpenTelemetry instrumentation via System.Diagnostics.ActivitySource. Your existing OpenTelemetry collectors will capture AMQP operations automatically without any additional configuration in this library.
Benchmarks
All benchmarks compare Oragon.RabbitMQ against hand-written native RabbitMQ.Client code performing the same DI scoping, serialization, try/catch, and ack/nack logic.
Environment: AMD Ryzen 9 9950X3D (16 cores / 32 threads), .NET 9.0.12, Windows 11, GC Server=True, BenchmarkDotNet v0.14.0.
Performance Summary
| Benchmark | Scenario | Oragon Overhead | Verdict |
|---|---|---|---|
| Concurrency Scaling | I/O-Bound (1000 msgs, Task.Delay) | 0 - 1% | Excellent - Zero overhead |
| Concurrency Scaling | CPU-Bound (1000 msgs, HashCode loop) | 2 - 8% | Very Good |
| Throughput | NoOp handler (1000-5000 msgs) | 0 - 11% | Good |
| Throughput | CPU-Bound handler | 0 - 14% | Good |
| Latency | Single message (all handlers) | 5 - 7% (~3.5 ms fixed) | Good |
| Allocation | Large messages (100 msgs) | 9% time, 1% memory | Excellent |
| RPC | ReplyAndAck vs native dedicated | -7% (Oragon wins) | Excellent |
RPC Performance
| Size | Native Dedicated (ms) | Oragon ReplyAndAck (ms) | Ratio |
|---|---|---|---|
| Small | 50.1 | 46.8 | 0.93 |
| Medium | 50.4 | 47.1 | 0.93 |
Oragon is 7% faster and allocates 17% less memory for RPC by reusing pre-warmed infrastructure.
Memory Allocation Summary
| Scenario | Oragon Overhead | Context |
|---|---|---|
| Large messages | ~1% | Message body dominates |
| Small messages (bulk) | ~20% | Fixed DI scope + pipeline cost |
| Single message latency | 2 - 3x | Fixed overhead dominates |
| RPC | 17% less | Reuses pre-warmed infrastructure |
Concurrency Scaling (I/O-Bound)
1000 messages with Task.Delay(5) handler. This is the most representative scenario for real-world workloads.
| Prefetch | Concurrency | Native (ms) | Oragon (ms) | Ratio |
|---|---|---|---|---|
| 10 | 2 | 2,700 | 2,706 | 1.00 |
| 10 | 4 | 1,380 | 1,390 | 1.01 |
| 10 | 8 | 728 | 731 | 1.00 |
| 50 | 4 | 1,351 | 1,357 | 1.00 |
| 50 | 8 | 694 | 694 | 1.00 |
| 100 | 4 | 1,347 | 1,352 | 1.00 |
| 100 | 8 | 677 | 681 | 1.01 |
Conclusion: Ratio consistently between 0.98 - 1.01. Zero latency overhead for I/O-bound workloads.
Key Takeaways
- I/O-bound workloads (the most common real-world scenario) — zero measurable overhead.
- CPU-bound with small messages (worst case) — 5-10% overhead from DI scope + dispatch pipeline.
- RPC — Oragon is faster and more memory-efficient than hand-written code.
- The overhead is predictable and constant: ~3.5 ms fixed per message + ~2.5 KB of fixed allocation. In production workloads with larger messages and heavier handlers, this fixed cost becomes irrelevant.
- Fair trade-off: For ~5% overhead in the worst case, Oragon provides: integrated DI, pluggable serialization, automatic error handling, declarative flow control, and a clean API.
Full benchmark results are available in
benchmarks/Oragon.RabbitMQ.Benchmarks/BenchmarkDotNet.Artifacts/results/.
<details> <summary><strong>Design Philosophy</strong></summary>
Decoupling Business Logic from Infrastructure
Oragon.RabbitMQ is designed to decouple RabbitMQ consumers from business logic. Your business code remains completely unaware of the queue consumption context — resulting in simple, decoupled, agnostic, reusable, and highly testable code.
Manual Acknowledgment by Default
This consumer is focused on creating resilient consumers using manual acknowledgments (autoAck: false). The automatic flow handles Ack/Nack/Reject so you don't have to, but you can take control at any time by returning IAmqpResult.
Dead-Lettering as Recommended Pattern
Both serialization failures (Reject) and processing failures (Nack) default to no requeue. This is intentional — configure dead-letter exchanges on your queues to capture failed messages for inspection, replay, or alerting.
</details>
Samples
- Standalone sample — minimal console worker
- .NET Aspire sample — full Aspire integration
Tech
Contributing
Contributions are welcome! Please open an issue or submit a pull request.
License
MIT — LUIZ CARLOS FARIA - ACADEMIA.DEV - MENSAGERIA.NET
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. 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
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.8)
- Microsoft.Extensions.Hosting.Abstractions (>= 10.0.8)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.8)
- OpenTelemetry.Exporter.OpenTelemetryProtocol (>= 1.15.3)
- OpenTelemetry.Extensions.Hosting (>= 1.15.3)
- OpenTelemetry.Instrumentation.AspNetCore (>= 1.15.2)
- OpenTelemetry.Instrumentation.Http (>= 1.15.1)
- OpenTelemetry.Instrumentation.Runtime (>= 1.15.1)
- Oragon.RabbitMQ.Abstractions (>= 1.8.0)
- Polly (>= 8.6.6)
- RabbitMQ.Client (>= 7.2.1)
-
net9.0
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 9.0.16)
- Microsoft.Extensions.Hosting.Abstractions (>= 9.0.16)
- Microsoft.Extensions.Logging.Abstractions (>= 9.0.16)
- OpenTelemetry.Exporter.OpenTelemetryProtocol (>= 1.15.3)
- OpenTelemetry.Extensions.Hosting (>= 1.15.3)
- OpenTelemetry.Instrumentation.AspNetCore (>= 1.15.2)
- OpenTelemetry.Instrumentation.Http (>= 1.15.1)
- OpenTelemetry.Instrumentation.Runtime (>= 1.15.1)
- Oragon.RabbitMQ.Abstractions (>= 1.8.0)
- Polly (>= 8.6.6)
- RabbitMQ.Client (>= 7.2.1)
NuGet packages (3)
Showing the top 3 NuGet packages that depend on Oragon.RabbitMQ:
| Package | Downloads |
|---|---|
|
Oragon.RabbitMQ.Serializer.SystemTextJson
Implements JSON serialization for RabbitMQ using System.Text.Json. Leverage fast and modern serialization for efficient message handling in RabbitMQ consumers. |
|
|
Oragon.RabbitMQ.Serializer.NewtonsoftJson
Implements JSON serialization for RabbitMQ using Newtonsoft.Json. Easily serialize and deserialize messages for effective communication in RabbitMQ consumers. |
|
|
NWERP.Infrastructure
Package Description |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.8.0 | 923 | 5/28/2026 |
| 1.7.0 | 149 | 5/27/2026 |
| 1.6.0 | 2,351 | 2/9/2026 |
| 1.5.2 | 1,979 | 9/4/2025 |
| 1.5.1 | 265 | 9/4/2025 |
| 1.5.0 | 264 | 9/4/2025 |
| 1.4.0 | 1,599 | 6/4/2025 |
| 1.3.0-beta | 304 | 4/16/2025 |
| 1.2.3-beta | 886 | 4/8/2025 |
| 1.2.2-beta | 262 | 4/7/2025 |
| 1.2.1-beta | 238 | 4/7/2025 |
| 1.2.0-beta | 256 | 4/7/2025 |
| 1.1.0 | 1,073 | 1/22/2025 |
| 1.0.0 | 238 | 12/26/2024 |
| 0.0.11 | 320 | 12/17/2024 |
| 0.0.9-beta | 172 | 10/19/2024 |
| 0.0.8-beta | 115 | 8/2/2024 |
| 0.0.7-beta | 156 | 6/22/2024 |
| 0.0.6-beta | 131 | 6/6/2024 |
| 0.0.5-beta | 158 | 6/5/2024 |