BunnyMQ 0.1.6

dotnet add package BunnyMQ --version 0.1.6
                    
NuGet\Install-Package BunnyMQ -Version 0.1.6
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="BunnyMQ" Version="0.1.6" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="BunnyMQ" Version="0.1.6" />
                    
Directory.Packages.props
<PackageReference Include="BunnyMQ" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add BunnyMQ --version 0.1.6
                    
#r "nuget: BunnyMQ, 0.1.6"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package BunnyMQ@0.1.6
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=BunnyMQ&version=0.1.6
                    
Install as a Cake Addin
#tool nuget:?package=BunnyMQ&version=0.1.6
                    
Install as a Cake Tool

Bunny

Controller-style RabbitMQ consumer/publisher for .NET 10. Route AMQP messages to handler methods with attributes — like ASP.NET controllers, but for the bus.

[Exchange("orders")]
public class OrderHandler(IOrderService orders, ILogger<OrderHandler> logger) : Bunny.EventHandler
{
    [Topic("order.{id:guid}.created")]
    public async Task<AckResult> OnCreated(Guid id, [FromBody] OrderCreatedDto dto, CancellationToken ct)
    {
        logger.LogInformation("Order {Id} from {RoutingKey}", id, RoutingKey);
        return await orders.TryHandle(dto, ct) ? Ack() : Nack(requeue: true);
    }
}

Why

The .NET ecosystem has plenty of RabbitMQ libraries — MassTransit, EasyNetQ, Rebus, raw RabbitMQ.Client. Each comes with its own mental model: sagas, consumers, message contexts, handlers, pipeline behaviors. Every team picks one and then reinvents how to organize code around it.

Bunny is opinionated about exactly that one thing: organize event handling the same way you organize REST controllers.

// REST controller — every .NET developer knows this shape
[Route("orders")]
public class OrdersController(IOrderService orders) : ControllerBase
{
    [HttpPost("{id:guid}/cancel")]
    public Task Cancel(Guid id, [FromBody] CancelDto dto) => orders.Cancel(id, dto);
}

// Bunny handler — same shape, AMQP routing key instead of an HTTP route
[Exchange("orders")]
public class OrderHandler(IOrderService orders) : Bunny.EventHandler
{
    [Topic("order.{id:guid}.cancel")]
    public Task Cancel(Guid id, [FromBody] CancelDto dto, CancellationToken ct) => orders.Cancel(id, dto, ct);
}

If you've ever written an ASP.NET controller, you already know Bunny. Class = group of related handlers. Method = one handler. Attribute = route. Return value = response. No new concepts to learn — even a developer who's never touched RabbitMQ can read a handler and understand what it does on the first try.

Trade-off: Bunny doesn't compete on features with MassTransit & co. No built-in sagas, no Outbox pattern, no cross-broker abstraction, no scheduling. It does one thing: attribute-routed AMQP handlers that look like REST controllers. Need more than that and you'll outgrow Bunny.

Install

dotnet add package BunnyMQ

Code still references the Bunny namespace (and assembly) — only the NuGet listing name is BunnyMQ (the simpler Bunny package id is taken on nuget.org by an unrelated project).

Or as a project reference during local development:

<ProjectReference Include="..\..\Libs\Bunny\Bunny\Bunny.csproj" />

Quick start

// Program.cs
builder.Services.AddBunny(b => b
    .ScanAssembly(typeof(Program).Assembly)
    .DeclareExchange("audit"));   // optional: publish-only exchanges
// appsettings.json
{
  "Bunny": {
    "HostName": "rabbitmq",
    "Port": 5672,
    "UserName": "guest",
    "Password": "guest",
    "VirtualHost": "/"
  }
}

Write a handler:

using EventHandler = Bunny.EventHandler;  // avoids clash with System.EventHandler delegate

[Exchange("orders")]
public class OrderHandler(IOrderService orders) : EventHandler
{
    [Topic("order.{id:guid}.created", Queue = "orders.created", Prefetch = 20)]
    public Task OnCreated(Guid id, [FromBody] OrderDto dto, CancellationToken ct) => orders.HandleAsync(id, dto, ct);
}

Publish from anywhere:

public class CheckoutService(IBunnyPublisher bus)
{
    public Task Emit(Order o, CancellationToken ct)
        => bus.PublishAsync("orders", $"order.{o.Id}.created", o, ct);
}

If a service only publishes (REST API, background job) and never consumes, use the lightweight AddBunnyPublisher — no scanning, no consumer channels:

builder.Services.AddBunnyPublisher(b => b
    .DeclareExchange("orders")
    .DeclareExchange("audit"));

Docs

  • Getting started — install, configure, write your first handler step-by-step
  • Examples & recipes — route params, publishing from handlers, early ack, custom serializers, poison messages

Repo layout

Bunny/                   <-- repo root
├── Bunny.sln
├── README.md
├── docs/
├── Bunny/               <-- library project
│   └── Bunny.csproj
└── Bunny.Tests/         <-- xUnit + NSubstitute + FluentAssertions
    └── Bunny.Tests.csproj

Build & test from the root:

dotnet build Bunny.sln
dotnet test  Bunny.sln

Features

  • Attribute routing: [Exchange] on class, [Topic("order.{id:guid}.created")] on methods
  • Typed route parameter binding: int, long, guid, string, bool, double, float
  • Scoped DI per message — DbContext & friends just work
  • Async pipeline end-to-end (RabbitMQ.Client v7)
  • Return-value ack: return Ack(); / Nack(requeue: true) / Reject() — or void for implicit ack
  • Early reply: AckNowAsync() / NackNowAsync() / RejectNowAsync() when you want to free the prefetch slot before finishing
  • Pluggable serialization (IBunnySerializer, STJ default)
  • Per-topic prefetch & requeue-on-error
  • Configurable connection (IOptions<BunnyOptions>)

Status

Alpha. Public API may change. No DLX / dead-letter helpers yet (configure on the queue directly). No retry policies. No publisher channel pool (single shared channel + semaphore).

License

MIT — see LICENSE.

Product 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

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
0.1.6 688 5/17/2026
0.1.5 104 5/17/2026
0.1.4 105 5/17/2026
0.1.3 106 5/17/2026