Enqueueing from Azure Service Bus queues

A common scenario is to have queues in Azure Service Bus that other systems sends messages to. Since many systems already have integrations to Azure Service Bus it makes it easy to consume events from such systems.

An option is of course to use the Azure.Messaging.ServiceBus NuGet package and process the messages using a ServiceBusProcessor and add any logic you need into the ProcessMessageAsync event handler to handle the message. Another option is to use the CommerceMind.Nexus.Azure package to take the messages from the service bus queue and place them in a Nexus queue.

Doing so lets you use virtual queues, idempotent messages and to store processed messages which can be very useful. But even if you don't need any of those features you'll benefit from the visibility, introspection and error handling of Nexus queues.

Reading from an Azure queue or topic into a Nexus queue

Start by installing the CommerceMind.Nexus.Azure NuGet package. After that you configure it like this in your Program.cs:

builder.Services
    .AddNexus()
    .AddQueues()
    .AddNexusAzureServiceBusQueues()
    .EnqueueFromAzureQueue<ExampleQueueMessage>("azure-queue")
    .Build()
;

By default Nexus will look for the connection string using IConfiguration.GetConnectionString("azureServiceBus") but you can add a loader func on the options object if you need to fetch it from somewhere else:

builder.Services
    .AddNexus()
    .AddQueues()
    .AddNexusAzureServiceBusQueues(options =>
    {
        options.ConnectionStringLoader = (serviceProvider, queueOrTopicName) =>
            "Endpoint=sb://xxx.servicebus.windows.net/;...";
    })
    .EnqueueFromAzureQueue<ExampleQueueMessage>("azure-queue")
    .Build()
;

If you want to read from a Service Bus Topic you also need to add a subscription name loader like this:

builder.Services
    .AddNexus()
    .AddQueues()
    .AddNexusAzureServiceBusQueues(options =>
    {
        options.SubscriptionNameLoader = (serviceProvider, topicName) => "my-subscription";
    })
    .EnqueueFromAzureTopic<ExampleQueueMessage>("azure-topic")
    .Build()
;

With the above example you also need a ExampleQueueMessage defined that implements IQueueMessage or IQueueMessageWithId. Read more about that in the Nexus queues intro.

The assumption is that the JSON on the Azure queue can be deserialized directly to the ExampleQueueMessage class. If that doesn't work for you it's possible to specify a separate type for the Azure message and also pass a function that maps the Azure message to the Nexus message like this:

public class ExampleQueueMessage : IQueueMessage
{
    public string SomeProperty { get; set;}
}

public class AzureQueueMessage
{
    public string SomeOtherProperty { get; set;}
}

builder.Services
    .AddNexus()
    .AddQueues()
    .AddNexusAzureServiceBusQueues()
    .EnqueueFromAzureQueue<ExampleQueueMessage, AzureQueueMessage>(
        "azure-queue",
        m => new ExampleQueueMessage { SomeProperty = m.SomeOtherProperty }
    )
    .Build()
;

The CommerceMind.Nexus.Azure package only expects there to be registered IEnqueuers for the message types used which means that it can enqueue to any of the underlying enqueuers; IVirtualEnqueuer, IDatabaseEnqueuer, a memory enqueuer or IApiEnqueuer.