![]() |
VOOZH | about |
dotnet add package Oragon.RabbitMQ.AspireClient --version 1.8.0
NuGet\Install-Package Oragon.RabbitMQ.AspireClient -Version 1.8.0
<PackageReference Include="Oragon.RabbitMQ.AspireClient" Version="1.8.0" />
<PackageVersion Include="Oragon.RabbitMQ.AspireClient" Version="1.8.0" />Directory.Packages.props
<PackageReference Include="Oragon.RabbitMQ.AspireClient" />Project file
paket add Oragon.RabbitMQ.AspireClient --version 1.8.0
#r "nuget: Oragon.RabbitMQ.AspireClient, 1.8.0"
#:package Oragon.RabbitMQ.AspireClient@1.8.0
#addin nuget:?package=Oragon.RabbitMQ.AspireClient&version=1.8.0Install as a Cake Addin
#tool nuget:?package=Oragon.RabbitMQ.AspireClient&version=1.8.0Install as a Cake Tool
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
👁 Quality Gate Status
👁 Bugs
👁 Code Smells
👁 Coverage
👁 Duplicated Lines (%)
👁 Reliability Rating
👁 Security Rating
👁 Technical Debt
👁 Maintainability Rating
👁 Vulnerabilities
Releases
👁 NuGet Version
👁 NuGet Downloads
👁 GitHub Tag
👁 GitHub Release
👁 MyGet Version
Project
👁 GitHub Repo stars
👁 GitHub last commit
👁 Roadmap
👁 .NET 9
👁 .NET 10
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.
MapQueue() pattern, zero learning curve for ASP.NET Core developers[FromServices], [FromBody], [FromAmqpHeader] attribute bindingOragon.RabbitMQ.AspireClientdotnet 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();
// 5. Map queue to handler
app.MapQueue("orders", ([FromServices] OrderService svc, OrderCreated msg) =>
svc.HandleAsync(msg));
app.Run();
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);
});
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);
}
});
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.
| 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) |
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));
By default, Oragon handles acknowledgments automatically:
BasicAckBasicReject (no requeue) — use dead-letteringBasicNack (no requeue) — use dead-letteringFor 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 |
| Attribute | Resolves from |
|---|---|
[FromServices] |
DI container (supports keyed services) |
[FromBody] |
Deserialized message body |
[FromAmqpHeader("key")] |
AMQP message header by key |
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 |
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 |
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.
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.
| 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 |
| 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.
| 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 |
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.
Full benchmark results are available in
benchmarks/Oragon.RabbitMQ.Benchmarks/BenchmarkDotNet.Artifacts/results/.
<details> <summary><strong>Design Philosophy</strong></summary>
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.
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.
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>
👁 C#
👁 .Net
👁 Visual Studio
👁 Jenkins
👁 Telegram
Contributions are welcome! Please open an issue or submit a pull request.
— LUIZ CARLOS FARIA - ACADEMIA.DEV - MENSAGERIA.NET
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net9.0 net9.0 is compatible. net9.0-android net9.0-android was computed. net9.0-browser net9.0-browser was computed. net9.0-ios net9.0-ios was computed. net9.0-maccatalyst net9.0-maccatalyst was computed. net9.0-macos net9.0-macos was computed. net9.0-tvos net9.0-tvos was computed. net9.0-windows net9.0-windows was computed. net10.0 net10.0 is compatible. net10.0-android net10.0-android was computed. net10.0-browser net10.0-browser was computed. net10.0-ios net10.0-ios was computed. net10.0-maccatalyst net10.0-maccatalyst was computed. net10.0-macos net10.0-macos was computed. net10.0-tvos net10.0-tvos was computed. net10.0-windows net10.0-windows was computed. |
Showing the top 1 NuGet packages that depend on Oragon.RabbitMQ.AspireClient:
| Package | Downloads |
|---|---|
|
NWERP.Infrastructure
Package Description |
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.8.0 | 611 | 5/28/2026 |
| 1.7.0 | 105 | 5/27/2026 |
| 1.6.0 | 2,114 | 2/9/2026 |
| 1.5.2 | 1,898 | 9/4/2025 |
| 1.5.1 | 223 | 9/4/2025 |
| 1.5.0 | 229 | 9/4/2025 |
| 1.4.0 | 474 | 6/4/2025 |
| 1.3.0-beta | 266 | 4/16/2025 |
| 1.2.3-beta | 908 | 4/8/2025 |
| 1.2.2-beta | 233 | 4/7/2025 |
| 1.2.1-beta | 236 | 4/7/2025 |
| 1.2.0-beta | 218 | 4/7/2025 |
| 1.1.0 | 357 | 1/22/2025 |
| 1.0.0 | 213 | 12/26/2024 |
| 0.0.11 | 205 | 12/17/2024 |
| 0.0.9-beta | 164 | 10/19/2024 |