Many thanks for JetBrains for providing Open Source Development license for best in class IDEs for this project.
RabbitMQ.Next is an experimental low-level RabbitMQ client for .Net with number of high-level APIs (created from scratch, no dependencies to another libraries, so no conflicts!). The motivation to create the library was to separate protocol-level code into a package that could be used as a base block for high-level API libraries. The second goal was to reduce allocation as much as possible and maintain reasonable performance. And the last it was sound cool to create a library that can work with sockets on low-level π.
The library was created with idea of the minimal possible allocation. Here is performance and allocations comparison with official dotnet driver:
Publisher benchmarks Find more details
Consumer benchmarks Find more details
(not that beautiful as publisher one, but I'm working on it)
Too much packages instead of a single... explained:
- RabbitMQ.Next, RabbitMQ.Next.Abstractions β core library, contains most of the protocol-level implementations
- RabbitMQ.Next.DependencyInjection - helper library for convenient registration of IConnection in DI container.
- RabbitMQ.Next.TopologyBuilder, RabbitMQ.Next.TopologyBuilder.Abstractions β library contains methods to manage exchanges, queues and bindings
- RabbitMQ.Next.Consumer, RabbitMQ.Next.Consumer.Abstractions β library provides high-level message consumption API
- RabbitMQ.Next.Publisher, RabbitMQ.Next.Publisher.Abstractions β provides high-level message publishing API
- RabbitMQ.Next.Publisher.Attributes β helper library that allow declarative attribute-based message initialization.
Serializers:
- RabbitMQ.Next.Serialization.PlainText β provides set of formatters for most common types to produce text/plain encoded messages
- RabbitMQ.Next.Serialization.SystemJson β json formatter that uses System.Text.Json under the hood
- RabbitMQ.Next.Serialization.MessagePack β formatter for popular MessagePack serializer
- RabbitMQ.Next.Serialization.NewtonsoftJson β formatter for popular NewtonsoftJson serializer
- RabbitMQ.Next.Serialization.Dynamic β formatter for advanced scenarios, when actual serializer should be selected based on the message properties (example)
More API and integration libraries are coming.
First of all have to open the connection to RabbitMQ server:
using RabbitMQ.Next;
...
var connection = ConnectionBuilder.Default
.UseConnectionString("amqp://guest:password@localhost:5672/")
.Build();
And basically that's it. Now all ready to make some useful stuff.
RabbitMQ.Next.TopologyBuilder library contains number of methods to manipulate exchanges, queues and bindings. Create an exchange and bind a queue - it's easy with the library. Complete code of Topology Builder example available here.
using RabbitMQ.Next.TopologyBuilder;
...
await connection.ConfigureAsync(async topology =>
{
await topology.Exchange.DeclareAsync("my-exchange", ExchangeType.Topic);
Console.WriteLine("'my-exchange' was created with using library defaults (durable by default)");
await topology.Exchange.DeclareAsync("my-advanced-exchange", ExchangeType.Topic,
builder => builder
.AutoDelete());
Console.WriteLine("'my-advanced-exchange' was created by explicitly configuring to be auto-delete");
Console.WriteLine("--------------------------------------------------------------");
await topology.Queue.DeclareQuorumAsync("my-queue");
Console.WriteLine("Declare quorum queue named 'my-queue'");
await topology.Queue.DeclareClassicAsync("my-advanced-queue",
builder => builder
.AutoDelete()
.MaxLength(1000));
Console.WriteLine("'my-advanced-queue' was created by explicitly configuring to be auto-delete and max-length 1000");
Console.WriteLine("--------------------------------------------------------------");
await topology.Queue.BindAsync("my-queue", "my-exchange", "cat");
await topology.Queue.BindAsync("my-queue", "my-exchange", "dog");
Console.WriteLine("my-queue was bound to my-exchange by 2 bindings.");
});
Message publisher and consumer require to use serializer, so library know how to format and parse message payloads. So far there are 3 serializers supported:
- RabbitMQ.Next.Serialization.PlainText
- RabbitMQ.Next.Serialization.SystemJson
- RabbitMQ.Next.Serialization.MessagePack
- RabbitMQ.Next.Serialization.NewtonsoftJson
- RabbitMQ.Next.Serialization.Dynamic (the one allow to choose serializer type basic on the message properties)
Serializer should be defined on the connection level, by using builder.UseSerializer
method, or via convenient extension methods. In case when different exchanges should use different type of serialization - use DynamicSerializer.
However, there is no rocket-science to implement other popular formats integration. Please post an issue in the issue tracker and I'll consider implementation of provide some code examples for you.
RabbitMQ.Next.Consumer library let client code to consume messages. Complete example is here
using RabbitMQ.Next.Consumer;
...
await using var consumer = connection.Consumer( // IConsumer implements IAsyncDisposable, do not forget to dispose it
builder => builder
.BindToQueue("test-queue") // It's possible to bind to multiple queues
.PrefetchCount(10)); // there are some more tweacks could be applied to consumer
// and start message consumption by providing handler and cancellation token
await consumer.ConsumeAsync(async message =>
{
Console.WriteLine($"Message received via '{message.Exchange}' exchange: {message.Content<string>()}");
}, cancellation.Token);
RabbitMQ.Next.Publisher library let client application to publish messages. Complete code is here.
using RabbitMQ.Next.Publisher;
...
await using var publisher = connection.Publisher("amq.fanout"); // IPublisher implements IAsyncDisposable, do not forget to dispose it
// And that's it, publisher is ready. There also some more tweaks could be applied to the publisher via publisher builder
// (for example disable Publisher confirms)
await publisher.PublishAsync("Some cool message");
// Also there is optional message builder, that could be used to set message properties
await publisher.PublishAsync("test message",
message => message
.Priority(5)
.Type("MyDto"));
This is how the last message looks like on the server:
RabbitMQ.Next.Publisher.Attributes let client code to initialize message properties from declarative attributes assigned to the DTO class or onto the assembly. This is not replacement for the RabbitMQ.Next.Publisher library, but convenient extension:
This example require to use some serializer that supports objects serialization, for example RabbitMQ.Next.Serialization.SystemJson
using RabbitMQ.Next.Publisher;
using RabbitMQ.Next.Publisher.Attributes;
...
// have to define DTO, and assign attributes on it
[PriorityAttribute(5)]
[TypeAttribute("MyDto")]
public class SampleDto
{
public string Title { get;set; }
}
...
// Small ammendments needed to publisher builder:
await using var publisher = connection.Publisher("amq.fanout",
builder => builder
.UseAttributesInitializer());
// and now it's ready for use
await publisher.PublishAsync(new SampleDto { Title = "test message" });
This is how the message is looks like:
Contributions to the package are always welcome!
- Report any bugs or issues you find on the issue tracker.
- You can grab the source code at the package's git repository.