Azure Service Bus client library for .NET


September 4, 2020

Azure Service Bus is an enterprise integration message broker. We need services like these to decouple various parts of our solutions. All major cloud providers offer similar services:

And in the open source world we have RabbitMQ which is also made available in the cloud as managed clusters by CloudAMQP.

Over the last few months, I have been playing with a number of services that Microsoft groups together as Azure Integration Services. This time around I decided to look into ways to interact with these services using the SDKs provided by Microsoft. In this post, I’ll show how easy it is to integrate a .NET application with Azure Service Bus.

Currently there are two Service Bus SDKs for .NET available as NuGet packages:

For my first foray into the world of Azure SDKs I decided to use the older version of the Service Bus SDK, given that the new one is still in preview. I document the steps below, and you will need an Azure subscription with a Service Bus Namespace and preferably a few Queues and Topics if you want to follow along.

Setting up the project

Start with the following on console. (I am using .NET Core 3.1.301).

dotnet new console -n AzureServiceBusSDKSample
cd AzureServiceBusSDKSample
dotnet add package Microsoft.Azure.ServiceBus --version 4.1.3
dotnet add package Microsoft.Extensions.Configuration
dotnet add package Microsoft.Extensions.Configuration.FileExtensions
dotnet add package Microsoft.Extensions.Configuration.Json

Here is my .csproj file. Note <LangVersion> and <CopyToOutputDirectory> here.

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp3.1</TargetFramework>
    <LangVersion>8.0</LangVersion>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Microsoft.Azure.ServiceBus" Version="4.1.3" />
    <PackageReference Include="Microsoft.Extensions.Configuration" Version="3.1.7" />
    <PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="3.1.7" />
    <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="3.1.7" />
  </ItemGroup>
  <ItemGroup>
      <None Update="appsettings.json">
         <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
      </None>
  </ItemGroup>
</Project>

This sets up the project nicely with references to Configuration API which we will use to store the connection string for Service Bus. We store the connection string in our appsettings.json file, and we can get the connection string from Azure portal.

Note that in real projects, connection strings should be not be kept in config files. A great place to keep connection strings is Azure Key Vault.

Calling Management Client APIs

The SDK provides a ManagementClient object which can be used to read and update properties of various objects associated with Service Bus. We need to supply a connection string to create a ManagementClient object.

IConfiguration config = new ConfigurationBuilder()
    .AddJsonFile("appsettings.json", true, true)
    .Build();
var connectionString = config["connectionString"];
var client = new ManagementClient(connectionString); 

With the ManagementClient object, we can call various methods to extract object information from Service Bus, e.g.

var queues = await client.GetQueuesAsync();
var topics = await client.GetTopicsAsync();

We can extract various properties from queues and topics collections.

foreach (var queue in queues)
{
    Console.WriteLine("Queue name: " + queue.Path);
    Console.WriteLine("Queue size in MB: " + queue.MaxSizeInMB);
    ...
}

The ManagementClient object also allows us to update parameters of queues, topics etc.

var queueDescription = await client.GetQueueAsync("replyqueue");
queueDescription.MaxDeliveryCount = 100;
await client.UpdateQueueAsync(queueDescription);

Sending message to a Queue or Topic

We can use QueueClientand TopicClient to pass messages to individual objects.

var queueClient = new QueueClient(connectionString, "replyqueue");  
await queueClient.SendAsync(new Message() { Body = Encoding.ASCII.GetBytes("Hello queue again")});
await queueClient.CloseAsync();

var topicClient = new TopicClient(connectionString, "new-topic"); 
await topicClient.SendAsync(new Message() {Body = Encoding.ASCII.GetBytes("Hello topic agian")});
await topicClient.CloseAsync();

In the case of a topic client, the message sent to the topic will be received by all subscriptions to that topic. Therefore, to test this in Azure portal, we need to create subscriptions against the topic we are using.

You can find the above code here.

Receive message from the Queue

To receive a message sent to a queue, you use RegisterMessageHandler of the QueueClient class.

client = new QueueClient(connectionString, "demoqueue4261");  

var messageHandlerOptions = new MessageHandlerOptions(ExceptionReceivedHandler)
{
    MaxConcurrentCalls = 1,
    AutoComplete = false
};

client.RegisterMessageHandler(ProcessMessagesAsync, messageHandlerOptions);

Below is a sample run of two console applications which shows how messages sent by the sender are read by the receiver. You can find the sender application here, and receiver application here.

Standard Normal Distribution

Subscribing to a Topic

The code to subscribe to a topic follows a very similar pattern. Instead of using TopicClient, we use SubscriptionClient. To make this demo work, we created a subscription via Azure Portal, but it is also possible to create subscriptions via a ManagementClient object, which we used above.

You can find the sender application here, and receiver application here.

Conclusion

The Service Bus SDK can be used to programmatically interact with Service Bus and perform administrative tasks using the ManagementClient class. To work with individual objects (e.g. passing messages to queues etc), we need to use the respective client objects (QueueClient, TopicClient, SubscriptionClient) as shown above.

In this post we have only scratched the surface of capabilities of the SDK. Depending upon the requirements of your application, play around with the SDK to learn about the features you need.