Skip to content

Topics

Wolverine supports publishing to Rabbit MQ topic exchanges with this usage:

cs
using var host = await Host.CreateDefaultBuilder()
    .UseWolverine(opts =>
    {
        opts.UseRabbitMq();

        opts.Publish(x =>
        {
            x.MessagesFromNamespace("SomeNamespace");
            x.ToRabbitTopics("topics-exchange", ex =>
            {
                // optionally configure the exchange
            });
        });

        opts.ListenToRabbitQueue("");
    }).StartAsync();

snippet source | anchor

While we're specifying the exchange name ("topics-exchange"), we did nothing to specify the topic name. With this set up, when you publish a message in this application like so:

cs
var publisher = host.Services.GetRequiredService<IMessageBus>();
await publisher.SendAsync(new Message1());

snippet source | anchor

You will be sending that message to the "topics-exchange" with a topic name derived from the message type. By default that topic name will be Wolverine's message type alias. Unless explicitly overridden, that alias is the full type name of the message type.

That topic name derivation can be overridden explicitly by placing the [Topic] attribute on a message type like so:

cs
[Topic("color.blue")]
public class FirstMessage
{
    public Guid Id { get; set; } = Guid.NewGuid();
}

snippet source | anchor

Of course, you can always explicitly send a message to a specific topic with this syntax:

cs
await publisher.BroadcastToTopicAsync("color.*", new Message1());

snippet source | anchor

Note two things about the code above:

  1. The IMessageBus.BroadcastToTopicAsync() method will fail if there is not the declared topic exchange endpoint that we configured above
  2. You can use Rabbit MQ topic matching patterns in addition to using the exact topic

Lastly, to set up listening to specific topic names or topic patterns, you just need to declare bindings between a topic name or pattern, the topics exchange, and the queues you're listening to in your application. Lot of words, here's some code from the Wolverine test suite:

cs
theSender = Host.CreateDefaultBuilder()
    .UseWolverine(opts =>
    {
        opts.UseRabbitMq("host=localhost;port=5672").AutoProvision();
        opts.PublishAllMessages().ToRabbitTopics("wolverine.topics", exchange =>
        {
            exchange.BindTopic("color.green").ToQueue("green");
            exchange.BindTopic("color.blue").ToQueue("blue");
            exchange.BindTopic("color.*").ToQueue("all");
        });

        opts.PublishMessagesToRabbitMqExchange<RoutedMessage>("wolverine.topics", m => m.TopicName);
    }).Start();

snippet source | anchor

Publishing by Topic Rule

As of Wolverine 1.16, you can specify publishing rules for messages by supplying the logic to determine the topic name from the message itself. Let's say that we have an interface that several of our message types implement like so:

cs
public interface ITenantMessage
{
    string TenantId { get; }
}

snippet source | anchor

Let's say that any message that implements that interface, we want published to the topic for that messages TenantId. We can implement that rule like so:

cs
using var host = await Host.CreateDefaultBuilder()
    .UseWolverine((context, opts) =>
    {
        opts.UseRabbitMq();

        // Publish any message that implements ITenantMessage to 
        // a Rabbit MQ "Topic" exchange named "tenant.messages"
        opts.PublishMessagesToRabbitMqExchange<ITenantMessage>("tenant.messages",m => $"{m.GetType().Name.ToLower()}/{m.TenantId}")
            
            // Specify or configure sending through Wolverine for all
            // messages through this Exchange
            .BufferedInMemory();
    })
    .StartAsync();

snippet source | anchor

Released under the MIT License.