# IBM MQ polymorphic event routing 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`: ```cs // Explicitly subscribe to both concrete types' topics when handling OrderPlaced ibmmq.Topology.SubscribeTo(); ibmmq.Topology.SubscribeTo(); ``` 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: ```bash 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 ```cs 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`). ```cs // Explicitly subscribe to both concrete types' topics when handling OrderPlaced ibmmq.Topology.SubscribeTo(); ibmmq.Topology.SubscribeTo(); ``` ### Publishing ```cs 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 ```cs sealed class OrderPlacedHandler : IHandleMessages { 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`.