Skip to content

Subscriptions & Message Routing

When you publish a message using IMessageBus or IMessageContext, Wolverine uses its concept of subscriptions to know how and where to send the message. Consider this code that publishes a PingMessage:

cs
public class SendingExample
{
    public async Task SendPingsAndPongs(IMessageContext bus)
    {
        // Publish a message
        await bus.SendAsync(new PingMessage());
    }
}

snippet source | anchor

When sending, publishing, scheduling, or invoking a message type for the first time, Wolverine runs through a series of rules to determine what endpoint(s) subscribes to the message type. Those rules in order of precedence are:

  1. Explicit subscription rules
  2. Use a local subscription using the conventional local queue routing if the message type has a known message handler within the application. This conventional routing to local queues can be disabled.
  3. Any registered message routing conventions like the Rabbit MQ or Amazon SQS routing conventions

Explicit Subscriptions

To route messages to specific endpoints, we can apply static message routing rules by using a routing rule as shown below:

cs
using var host = Host.CreateDefaultBuilder()
    .UseWolverine(opts =>
    {
        // Route a single message type
        opts.PublishMessage<PingMessage>()
            .ToServerAndPort("server", 1111);

        // Send every possible message to a TCP listener
        // on this box at port 2222
        opts.PublishAllMessages().ToPort(2222);

        // Or use a more fluent interface style
        opts.Publish().MessagesFromAssembly(typeof(PingMessage).Assembly)
            .ToPort(3333);

        // Complicated rules, I don't think folks will use this much
        opts.Publish(rule =>
        {
            // Apply as many message matching
            // rules as you need

            // Specific message types
            rule.Message<PingMessage>();
            rule.Message<Message1>();

            // Implementing a specific marker interface or common base class
            rule.MessagesImplementing<IEventMarker>();

            // All types in a certain assembly
            rule.MessagesFromAssemblyContaining<PingMessage>();

            // or this
            rule.MessagesFromAssembly(typeof(PingMessage).Assembly);

            // or by namespace
            rule.MessagesFromNamespace("MyMessageLibrary");
            rule.MessagesFromNamespaceContaining<PingMessage>();

            // Express the subscribers
            rule.ToPort(1111);
            rule.ToPort(2222);
        });

        // Or you just send all messages to a certain endpoint
        opts.PublishAllMessages().ToPort(3333);
    }).StartAsync();

snippet source | anchor

Do note that doing the message type filtering by namespace will also include child namespaces. In our own usage we try to rely on either namespace rules or by using shared message assemblies.

Released under the MIT License.