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:
- Google offers a Pub/Sub service.
- AWS has Simple Queue Service (SQS) and <a href="https://aws.amazon.com/sns"target=”_blank">Simple Notification Service (SNS).
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:
Microsoft.Azure.ServiceBus which seems to have been released in 2017 and is at version 4.1.3 at the time of writing.
Azure.Messaging.ServiceBus which looks like a much more recent project kicked off in 2020, and is more active on GitHub. At the time of this writing it is still in preview.
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 QueueClient
and 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.
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.