Getting Started
Architecture
NServiceBus
Transports
Persistence
ServiceInsight
ServicePulse
ServiceControl
Monitoring
Modernization
Samples

IBM MQ polymorphic event routing

Component: IBM MQ Transport
NuGet Package: NServiceBus.Transport.IBMMQ 1.x
Target Version: NServiceBus 10.x

This sample demonstrates explicit polymorphic event routing with the IBM MQ transport. An Orders endpoint publishes either an OrderPlaced or an ExpressOrderPlaced event. The Shipping endpoint has a handler for OrderPlaced and uses explicit subscription routes to receive both event types.

How it works

The IBM MQ transport uses a topic-per-event model: each concrete event type is published to its own topic. Subscribing to OrderPlaced alone would only create a subscription on the OrderPlaced topic, missing messages published as ExpressOrderPlaced.

To receive both, the subscriber explicitly maps the OrderPlaced subscription to multiple topics using SubscribeTo:

// Explicitly subscribe to both concrete types' topics when handling OrderPlaced
ibmmq.Topology.SubscribeTo<OrderPlaced, OrderPlaced>();
ibmmq.Topology.SubscribeTo<OrderPlaced, ExpressOrderPlaced>();

NServiceBus includes all types in the .NET inheritance chain in the NServiceBus.EnclosedMessageTypes message header when publishing. The handler for OrderPlaced receives the full ExpressOrderPlaced instance because NServiceBus matches the enclosed type chain against registered handlers.

Prerequisites

The sample requires a running IBM MQ broker. A Docker Compose file is included:

docker compose up -d

This starts IBM MQ with queue manager QM1 on port 1414. The management console is available at https://localhost:9443/ibmmq/console (credentials: admin / passw0rd).

Running the sample

  1. Start Shipping first. EnableInstallers() creates its queue, topics, and durable subscriptions on the broker.
  2. Start Orders.
  3. Press O - Shipping logs Received OrderPlaced.
  4. Press E - Shipping logs Received ExpressOrderPlaced, delivered via the explicit subscription on the ExpressOrderPlaced topic.

Code walk-through

Event hierarchy

public record OrderPlaced(Guid OrderId, string Product) : IEvent;

public record ExpressOrderPlaced(Guid OrderId, string Product)
    : OrderPlaced(OrderId, Product);

ExpressOrderPlaced inherits from OrderPlaced using C# record inheritance.

Subscription routing

The subscriber must explicitly declare which concrete types' topics to subscribe to. Without this, the transport throws an InvalidOperationException at startup because OrderPlaced has a known descendant type (ExpressOrderPlaced).

// Explicitly subscribe to both concrete types' topics when handling OrderPlaced
ibmmq.Topology.SubscribeTo<OrderPlaced, OrderPlaced>();
ibmmq.Topology.SubscribeTo<OrderPlaced, ExpressOrderPlaced>();

Publishing

if (key.Key == ConsoleKey.E)
{
    await session.Publish(new ExpressOrderPlaced(orderId, "Widget"));
    Console.WriteLine($"Published ExpressOrderPlaced {orderId}");
}
else if (key.Key == ConsoleKey.O)
{
    await session.Publish(new OrderPlaced(orderId, "Widget"));
    Console.WriteLine($"Published OrderPlaced {orderId}");
}

Both events are published with the same session.Publish call. Each is published to its own topic (DEV.ORDERPLACED and DEV.EXPRESSORDERPLACED respectively). NServiceBus populates NServiceBus.EnclosedMessageTypes with the full type chain automatically.

Subscriber handler

sealed class OrderPlacedHandler : IHandleMessages<OrderPlaced>
{
    public Task Handle(OrderPlaced message, IMessageHandlerContext context)
    {
        var messageType = message.GetType().Name;
        Console.WriteLine($"Received {messageType}: OrderId={message.OrderId}, Product={message.Product}");
        return Task.CompletedTask;
    }
}

The handler is registered for OrderPlaced only. Logging message.GetType().Name confirms the full derived type is preserved through delivery - the handler receives an ExpressOrderPlaced instance, not a downcast OrderPlaced.

Related Articles

  • IBM MQ Transport
    Integrate NServiceBus with IBM MQ for enterprise messaging on mainframe and distributed platforms.
  • Messages, events, and commands
    Messages as commands or events are the the unit of communication for message-based distributed systems. NServiceBus ensures they are used correctly.
  • Publish-Subscribe
    Subscribers tell the publisher they are interested. Publishers store addresses for sending messages.
  • Publish/subscribe topology
    How the IBM MQ transport implements publish/subscribe messaging using topics and durable subscriptions.