Polymorphic events with Azure Service Bus Transport

Component: Azure Service Bus Transport
NuGet Package NServiceBus.Azure.Transports.WindowsAzureServiceBus (8-pre)
Target NServiceBus Version: 7.x
This page targets a pre-release version and is subject to change prior to the final release.
For proper polymorphic events support, use ForwardingTopology. This sample should only be used in case 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 and handles BaseEvent and DerivedEvent events.

DerivedEvent event is derived from BaseEvent event. The difference between the two events is an additional piece of information provided with the DerivedEvent in form of the Data property.

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 BaseEvent or DerivedEvent type 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 2 subscriptions, one for each event.

Auto subscription behavior

Normally, this would be fine. Though not with ASB transport and polymorphic events. Each subscription is filtering messages based on NServiceBus.EnclosedMessageTypes header. When an event of BaseType is published, it's going only into Samples.ASB.Polymorphic.Subscriber.BaseEvent subscription as per image below.

In Versions 7 and above 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. NServiceBus Subscriber endpoint will invoke handlers for each type that message implements. 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 address

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, 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 BaseEvent subscription serving as "catch-all".

Results of the sample now adhere 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