Polymorphic events with the Azure Service Bus transport

Component: Azure Service Bus Transport
NuGet Package NServiceBus.Azure.Transports.WindowsAzureServiceBus (7.x)
Target NServiceBus Version: 6.x
For true polymorphic events support, use the ForwardingTopology. This sample should be used only if EndpointOrientedTopology is required.

Prerequisites

An environment variable named AzureServiceBus.ConnectionString with the connection string for the Azure Service Bus namespace.

Azure Service Bus Transport

This sample utilizes the Azure Service Bus Transport.

Code walk-through

This sample has two endpoints:

  • Publisher publishes BaseEvent and DerivedEvent events.
  • Subscriber subscribes to and handles BaseEvent and DerivedEvent events.

DerivedEvent derives from BaseEvent. The difference between the two events is the Data property provided with DerivedEvent.

public class BaseEvent :
    IEvent
{
    public Guid EventId { get; set; }
}
public class DerivedEvent :
    BaseEvent
{
    public string Data { get; set; }
}

Publisher

The Publisher will publish an event of type BaseEvent or DerivedEvent based on the input it receives from the console.

Subscriber

By default, all events handled in Subscriber will be auto-subscribed. Default topology subscription behavior will create two subscriptions, one for each event.

Auto-subscription behavior

Normally, this would be fine. Not so with ASB transport and polymorphic events. Each subscription is filtering messages based on the NServiceBus.EnclosedMessageTypes header. When an event of BaseType is published, it's going only into Samples.ASB.Polymorphic.Subscriber.BaseEvent subscription:

In version 7 and above of the transport, polymorphic events are supported with auto-subscription turned on when ForwardingTopology is used.

But whenever DerivedEvent event is published, both Samples.ASB.Polymorphic.Subscriber.BaseEvent and Samples.ASB.Polymorphic.Subscriber.DerivedEvent subscriptions get a copy of that message:

Since DerivedEvent implements BaseEvent, it's NServiceBus.EnclosedMessageTypes header will contain both types:

Events.DerivedEvent, Shared, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null;
Events.BaseEvent, Shared, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null

Both filters will pick the DerivedEvent message, causing duplicate delivery to the Subscriber. The NServiceBus Subscriber endpoint will invoke handlers for each type that message implements. The end result will be multiple invocations for the same message.

DerivedEvent sent. EventId: c3c07de2-433f-4b31-8f76-1b9826409471
2015-11-02 13:00:37.655 INFO  DerivedEventHandler Received DerivedEvent. EventId: c3c07de2-433f-4b31-8f76-1b9826409471 Data: more data
2015-11-02 13:00:39.415 INFO  BaseEventHandler Received BaseEvent. EventId: c3c07de2-433f-4b31-8f76-1b9826409471
2015-11-02 13:00:39.500 INFO  DerivedEventHandler Received DerivedEvent. EventId: c3c07de2-433f-4b31-8f76-1b9826409471 Data: more data
2015-11-02 13:00:39.505 INFO  BaseEventHandler Received BaseEvent. EventId: c3c07de2-433f-4b31-8f76-1b9826409471

How to restrict the message handlers

To address this in general and allow proper handling of polymorphic events, Subscriber has do the following:

  1. Disable automatic subscription.
  2. Subscribe explicitly to the base events only of polymorphic events.
  3. Subscribe explicitly to the non-polymorphic events it's interested in.
endpointConfiguration.DisableFeature<AutoSubscribe>();

When an event is a polymorphic event, such as DerivedEvent, the endpoint will subscribe to the base event only.

await endpointInstance.Subscribe<BaseEvent>()
    .ConfigureAwait(false);

For this sample, configuring Subscriber as described above will create the topology that only has the BaseEvent subscription serving as "catch-all".

The sample now adheres to the expected polymorphic message handling

DerivedEvent sent. EventId: c23951b0-0864-4c35-8314-25f354d07d7d
2015-11-02 13:22:31.165 INFO  DerivedEventHandler Received DerivedEvent. EventId: c23951b0-0864-4c35-8314-25f354d07d7d Data: more data
2015-11-02 13:22:31.175 INFO  BaseEventHandler Received BaseEvent. EventId: c23951b0-0864-4c35-8314-25f354d07d7d
From Versions 7 and above, publisher names have to be configured via code for the subscribers.
topology.RegisterPublisher(typeof(BaseEvent), "Samples.ASB.Polymorphic.Publisher");

Samples

Related Articles


Last modified