Monthly Archives: October 2018

Managing ServiceBus queues, topics and subscriptions in .Net Core

From version 3.1 of Microsoft.Azure.ServiceBus it is finally possible to manage queues, topics and subscriptions in .Net Core. Let’s have a look at how we can use it in real life scenarios.

Previously we would use sample code for getting a queue:

public IQueueClient GetQueueClient(string _serviceBusConnectionString, string _queueName)
{
    var queueClient = new QueueClient(_serviceBusConnectionString, _queueName);
    return queueClient;
}

Using ManagementClient we can write much better code.

public async Task<IQueueClient> GetOrCreateQueue(string _serviceBusConnectionString, string _queueName)
{
    var managementClient = new ManagementClient(_serviceBusConnectionString);
    if (!(await managementClient.QueueExistsAsync(_queueName)))
    {
        await managementClient.CreateQueueAsync(new QueueDescription(_queueName));
    }

    var queueClient = new QueueClient(_serviceBusConnectionString, _queueName);
    return queueClient;
}

Now before getting a queue, we are checking if a queue exists and if not, we are creating it. So when executing this code:

manager.GetOrCreateQueue(configuration["ServiceBusConnectionString"], "createTest").GetAwaiter().GetResult();

We will get a queue that we can use.

Customizing your ServiceBus subscription

It is pretty easy to create a topic subscription or a queue, but SubscriptionDescription object offers a lot more then just that. This is a simple code that creates a subscription:

public async Task<ISubscriptionClient> GetOrCreateTopicSubscription(string serviceBusConnectionString, string topicPath, string subscriptionName)
{
    var managementClient = new ManagementClient(serviceBusConnectionString);
    if (!(await managementClient.SubscriptionExistsAsync(topicPath, subscriptionName)))
    {
        await managementClient.CreateSubscriptionAsync(new SubscriptionDescription(topicPath, subscriptionName));
    }

    var subscriptionClient = new SubscriptionClient(serviceBusConnectionString, topicPath, subscriptionName);
    return subscriptionClient;
}

Let’s have a look at a few most important properties:

TopicPath The path of the topic that this subscription description belongs to
Name Name of the subscription
DefaultMessageTimeToLive This is the duration after which the message expires, starting from when the message is sent to the Service Bus. After that time, the message will be removed from a subscription
EnableDeadLetteringOnMessageExpiration Support for dead-letter queue. When you enable it, messages will come here instead of being removed from the main queue
EnableBatchedOperations It’s a good idea to set it to true, no matter if the reader supports batch operations or not. Doing things in batches is usually faster
LockDuration This is the duration for which message can be locked for processing
MaxDeliveryCount Maximum count of message returning to the subscription after failure processing. After that count message will be removed from the subscription

Let’s have a look what we can fill in in a real project.

public async Task<ISubscriptionClient> GetOrCreateTopicSubscription(string serviceBusConnectionString, string topicPath, string subscriptionName)
{
    var managementClient = new ManagementClient(serviceBusConnectionString);
    if (!(await managementClient.SubscriptionExistsAsync(topicPath, subscriptionName)))
    {
        await managementClient.CreateSubscriptionAsync(
            new SubscriptionDescription(topicPath, subscriptionName)
            {
                EnableBatchedOperations = true,
                AutoDeleteOnIdle = System.TimeSpan.FromDays(100),
                EnableDeadLetteringOnMessageExpiration = true,
                DefaultMessageTimeToLive = System.TimeSpan.FromDays(100),
                MaxDeliveryCount = 100,
                LockDuration = System.TimeSpan.FromMinutes(5)
            });
    }

    var subscriptionClient = new SubscriptionClient(serviceBusConnectionString, topicPath, subscriptionName);
    return subscriptionClient;
}

AutoDeleteOnIdle – subscription will be removed from the topic after 100 days idle – that is very unlikely. DefaultMessageTimeToLive and EnableDeadLetteringOnMessageExpiration – messages will be kept in the queue for very long – 100 days, then they will be sent to a dead letter queue. MaxDeliveryCount and LockDuration – message will be processed up to 100 times and for a maximum of 5 minutes.

We can do one more thing. When testing a project while development locally it’s ideal to work with real data. In the real case, we would probably have different Service Bus namespace and separate connection string for every environment. There is, however, a trick to use DEV data locally – just create your testing subscription! This is how it can look like:

    public async Task<ISubscriptionClient> GetOrCreateTopicSubscription(string serviceBusConnectionString, string topicPath, string subscriptionName)
    {
        var managementClient = new ManagementClient(serviceBusConnectionString);
#if DEBUG
        if (!(await managementClient.SubscriptionExistsAsync(topicPath, subscriptionName + "_MikTesting")))
        {
            await managementClient.CreateSubscriptionAsync(
                new SubscriptionDescription(topicPath, subscriptionName + "_MikTesting")
                {
                    EnableBatchedOperations = true,
                    AutoDeleteOnIdle = System.TimeSpan.FromDays(100),
                    EnableDeadLetteringOnMessageExpiration = false,
                    DefaultMessageTimeToLive = System.TimeSpan.FromDays(2),
                    MaxDeliveryCount = 5,
                    LockDuration = System.TimeSpan.FromMinutes(5)
                });
        }
#else       
        if (!(await managementClient.SubscriptionExistsAsync(topicPath, subscriptionName)))
        {
            await managementClient.CreateSubscriptionAsync(
            new SubscriptionDescription(topicPath, subscriptionName)
            {
                EnableBatchedOperations = true,
                AutoDeleteOnIdle = System.TimeSpan.FromDays(100),
                EnableDeadLetteringOnMessageExpiration = true,
                DefaultMessageTimeToLive = System.TimeSpan.FromDays(100),
                MaxDeliveryCount = 100,
                LockDuration = System.TimeSpan.FromMinutes(5)
            });
        }
#endif
        var subscriptionClient = new SubscriptionClient(serviceBusConnectionString, topicPath, subscriptionName);
        return subscriptionClient;
    }

Testing subscription will have it’s own name, it will still be there up to 100 days of idle, but messages will be kept only for 2 days and they will not end up in dead letter queue. MaxDeliveryCount is only 5, cause if something goes wrong, we will end up having 5 the same errors in logs instead of 100 and this is much more likely to happen when testing locally.

Hope you found it useful, every code posted here is in my GitHub repository: https://github.com/mikuam/Blog

If you’re interested in more posts about Service Bus in .Net Core, have a look at: