Azure  

How to Send and Receive Messages from Azure Service Bus using .NET Client Library?

In this article, let’s create Azure Service Bus resources, Azure Service Bus namespace and Queue using Azure CLI. Assign “Azure Service Bus Data Owner” role to Microsoft Entra (Azure AD) user name. Build a .NET console application using Azure.Messaging.ServiceBus SDK to send and receive the messages. Sign in to Azure and run the application. After this exercise, you will be able to send and receive messages from Azure Service Bus using .NET Client Library.

Following tasks are performed in this article:

  • Create Azure Service Bus resources.

  • Create Azure Service Bus namespace and queue.

  • Assign role to Microsoft Entra (Azure AD) username.

  • Send and Receive Messages using .NET Client Library.

  • Sign in to Azure and run Application.

  • Clean up resources.

Create Azure Service Bus resources

First basic task is to create and make ready Azure Service Bus resources to Azure using Azure CLI. Azure CLI (Azure Cloud Shell) is used to create the required resources. Azure CLI is the free Bash shell which can be run directly within the Azure portal. That is preinstalled and configured within the account. Perform the below steps one by one to achieve this.

Use Azure CLI (Azure Cloud Shell)

It is a free Bash shell which can be run directly within the Azure portal. It is preinstalled and configured within an account.

  • Click Cloud Shell button on the menu bar at the top right side of the Azure portal.

    Cloud Shell button
  • It will launch an interactive shell which can be used to run the steps outlined in this article. Select a Bash environment. To use code editor In cloud shell toolbar go to Settings menu and then select Go to Classic version.

    Cloud Shell Bash
  • Create resource group - Resource group is a logical container used to hold related resources. In it include the resources which you want to manage as a group. App configuration resource belongs to this resource group. Create it using az group create command.

az group create \ 
     --name myResourceGroup1 \ 
     --location eastus2 
  • eastus2 is location code instead of it one can use their nearest region location.

  • Create variables - Here, several commands require unique names/values with same parameters. Hence, for easy to manege lets create some variables, assign values and reuse them in the command parameters. let command is used as below to create required variables.

let resourceGroup=myResourceGroup1 \
     location=eastus2 \
     namespaceName=myServiceBusNameSpace$RANDOM

Create Azure Service Bus namespace and Queue

In this section, lets create a Service Bus namespace, and then create a Queue. One by one perform the following steps in Azure CLI to achieve this.

Create Azure Service Bus namespace

az servicebus namespace create command is used to create an Azure Service Bus namespace and it will be used in .NET console application. This namespace is the logical container for service bus resources in Azure. It provides a unique container which allows to create one or more service bus.

az servicebus namespace create \
     --name $namespaceName \
     --location $location \
     --resource-group $resourceGroup

Create Queue

Below az servicebus queue create command is used to create a Queue with name myQueue inside above created Service Bus namespace. This queue will be used to hold the messages.

az servicebus queue create \
     --name myQueue \
     --resource-group $resourceGroup \
     --namespace-name $namespaceName

Assign role to Microsoft Entra (Azure AD) user

Let’s assign Microsoft Entra user to “Azure Service Bus Data Owner” role at the Service Bus namespace level to allow console application to send and receive messages. It is important to assign roles to Microsoft Entra (Azure AD) user name. Roles will define what access and permissions a user has within an organization’s Microsoft cloud environment. Roles determine what resources and actions a user can perform. “Azure Service Bus Data Owner” role is to be assigned to Microsoft Entra user which allows application to send and receive messages. One by one perform below steps in Azure CLI.

Retrieve userPrincipalName

First, retrieve userPrincipalName from account as mentioned in following command. It retrieves the information about currently authenticated user including their UPN and represents that who the role will be assigned to.

userPrincipal=$(az rest \
     --method GET  \
     --url https://graph.microsoft.com/v1.0/me \
     --headers 'Content-Type=application/json' \
     --query userPrincipalName 
     --output tsv)

Retrieve resource ID

Second, get the resource ID of Service Bus namespace using below command. This will be used in next step to set scope for role assignment. Resource ID sets scope for role assignment to specific namespace.

resourceID=$(az servicebus namespace show \
     --resource-group $resourceGroup \
     --name $namespaceName\ 
     --query id \
     --output tsv)

Create and assign “Azure Service Bus Data Owner” role

Finally, create and assign “Azure Service Bus Data Owner” role using az role assignment create command. Command execution will create and assign “Azure Service Bus Data Owner” role which gives permission to send and receive the messages. This will give permissions to manage next routines. userPrincipal and resourceID variables are created in first and second steps which are used in this command to receive actual value at command execution time.

az role assignment create \
     --assignee $userPrincipal\
     --role "Azure Service Bus Data Owner" \
     --scope $resourceID

Now, required basic resources are deployed and ready to use in console application.

Send and Receive Messages using .NET Client Library

Let’s set-up the .NET console application to send and receive the messages using .NET Client Library. Perform the following steps one by one in to Cloud Shell to achieve this.

.NET Project Setup

Set up one console application to send and receive message using .NET Client Library.

  • Create project directory and change to that directory. First create a directory for the project using below command and move to that directory.

mkdir servicebus1
cd servicebus1
  • Create .NET console application to add and fetch secrets through it. dotnet new console command is used to create a .NET console app.

dotnet new console
  • Install Packages - run dotnet add package command to add Azure.Identity and Azure.Messaging.ServiceBus packages in project to use the SDK.

dotnet add package Azure.Identity
dotnet add package Azure.Messaging.ServiceBus

Starter Code

Add the below starter code into the project and replace template code in Program.cs file by using editor in Cloud Shell.

  • Application editing - open Program.cs file to edit it in the Azure CLI using code command.

code Program.cs
  • Code replacing - replace existing code of Program.cs with the below code. This is the initial starter code and will replace last three commented lines with actual code in next “Complete code” section. Replace MY_NAMESPACE with actual service bus namespace.

using System;
using System.Timers;
using Azure.Identity;
using Azure.Messaging.ServiceBus;

// Replace MY_NAMESPACE with actual Service Bus namespace
string serviceBusClientNameSpace = "MY_NAMESPACE.servicebus.windows.net";
string queueName = "myQueue";

// CREATE SERVICE BUS CLIENT

// SEND MESSAGES TO QUEUE

// PROCESS MESSAGES FROM QUEUE

// Dispose client
await objServiceBusClient.DisposeAsync();
  • Save & close - Press ctrl + s to save your changes and continue.

Complete Code

Add following code one by one at mentioned commented section to complete the application. Let’s update the code for commented lines for specific operations one by one as described to create a service bus client to send messages to the queue and then process messages from the queue.

  • Create service bus client - In this section, let’s create DefaultAzureCredentialOptions object to configure DefaultAzureCredential credentials and then create a service bus client. Locate // CREATE SERVICE BUS CLIENT comment, then add following code directly beneath comment.

// CREATE SERVICE BUS CLIENT

// Create DefaultAzureCredentialOptions object to configure DefaultAzureCredential credentials
DefaultAzureCredentialOptions objDefaultAzureCredentialOptions = new()
{
     ExcludeEnvironmentCredential = true,
     ExcludeManagedIdentityCredential = true
};

// Create service bus client
ServiceBusClient objServiceBusClient = new(serviceBusClientNameSpace, new      DefaultAzureCredential(objDefaultAzureCredentialOptions));
  • Send messages to queue - First, create a service bus sender and then create service bus message batch. Second, set total number of message to be sent to queue and add message to batch. Third, use producer client to send batch of messages to service bus queue. Locate // SEND MESSAGES TO QUEUE comment, then add following code directly beneath comment.

// SEND MESSAGES TO QUEUE

// Create service bus sender
ServiceBusSender objServiceBusSender = objServiceBusClient.CreateSender(queueName);

// Create service bus message batch 
using ServiceBusMessageBatch objServiceBusMessageBatch = await objServiceBusSender.CreateMessageBatchAsync();

// Total number of message to be sent to queue
const int numberOfMessages = 4;

// Add random number to message 
var random = new Random();
for (int i = 1; i <= numberOfMessages; i++)
{
     int randomNumber = random.Next(1, 101);
     string messageBody = $"Message - {randomNumber}";
     
     // Add message to batch
     if (!objServiceBusMessageBatch.TryAddMessage(new ServiceBusMessage(messageBody)))
     {
          // Generate error message if message is too large for batch
          throw new Exception($"Message {i} is too large for batch and can't be sent!");
     }
}
try
{
     // Use producer client to send batch of messages to service bus queue
     await objServiceBusSender.SendMessagesAsync(objServiceBusMessageBatch);
     Console.WriteLine($"Batch of {numberOfMessages} messages has been published to queue successfully!");
}
finally
{
     // Cleaned up network resources and other not managed objects
     await objServiceBusSender.DisposeAsync();
}
Console.WriteLine("Press any key to receive and display messages!");
Console.ReadKey();
  • Process messages from queue - Locate // PROCESS MESSAGES FROM QUEUE comment, then add following code directly beneath comment. First, create a processor to process messages in queue and set idle timer timeout to stop processor for no messages in queue to process. Second, add handler to process messages and errors if any. Third, wait processor when to stop and display received messages.

// PROCESS MESSAGES FROM QUEUE

// Create processor to process messages in queue
ServiceBusProcessor objServiceBusProcessor = objServiceBusClient.CreateProcessor(queueName, new ServiceBusProcessorOptions());

// Set idle timer timeout to stop processor for no messages in queue to process
const int idleTimeOutMilliSeconds = 3000;
System.Timers.Timer idleTimer = new(idleTimeOutMilliSeconds);

idleTimer.Elapsed += async (s, e) =>
{
     Console.WriteLine($"No messages received for {idleTimeOutMilliSeconds / 1000} seconds. Processor has been stopped!");
     await objServiceBusProcessor.StopProcessingAsync();
};

try
{
     // Add handler to process messages
     objServiceBusProcessor.ProcessMessageAsync += MessageHandler;

     // Add handler to process errors if any
     objServiceBusProcessor.ProcessErrorAsync += ErrorHandler;
    
     // Start processing 
     idleTimer.Start();
     await objServiceBusProcessor.StartProcessingAsync();
     Console.WriteLine($"Processor has been started and it will stop after {idleTimeOutMilliSeconds / 1000} seconds of inactivity!");
    
     // Wait processor when to stop
     while (objServiceBusProcessor.IsProcessing)
     {
          await Task.Delay(500);
     }
     idleTimer.Stop();
     Console.WriteLine("All messages have been received successfully!");
     Console.WriteLine("Press any key to Exit!");
     Console.ReadKey();
}
finally
{
     // Dispose processor
     await objServiceBusProcessor.DisposeAsync();
}

// Display received messages
async Task MessageHandler(ProcessMessageEventArgs args)
{
     string body = args.Message.Body.ToString();
     Console.WriteLine($"Message received: {body}");
     
     // Reset idle timer on each message
     idleTimer.Stop();
     idleTimer.Start();
    
     // Complete message to delete from queue
     await args.CompleteMessageAsync(args.Message);
}

// Generate error message if error occured during receiving messages
Task ErrorHandler(ProcessErrorEventArgs args)
{
     Console.WriteLine(args.Exception.ToString());
     return Task.CompletedTask;
}
  • Save & Close - Now it’s time to save and close the file by pressing Ctrl + s to save file and then Ctrl + q to exit the editor. Here, by with this article a complete code is attached in Program.cs file.

Sign in to Azure and run Application

Now application is ready to run. One by one execute the following commands in Azure CLI to run an application and perform the mentioned steps to verify the result outcomes.

  • Sign in - az login command used for sign in. Sign in to Azure is mandatory even though Cloud Shell session already may have authenticated.

az login
  • Run Application - dotnet run command used to start console application. Application will display appropriate messages as mentioned in output section.

dotnet run
  • Output - Application will display print messages on console as below. Here, application will send four messages to service bus as set in the code. The random number is used to set with each message to distinguish each message.

Batch of 4 messages has been published to queue successfully!
Press any key to receive and display messages!
Processor has been started and it will stop after 3 seconds of inactivity!
Message received: Message - 7
Message received: Message - 43
Message received: Message - 75
Message received: Message - 21
No messages received for 3 seconds. Processor has been stopped!
All messages have been received successfully!
Press any key to Exit!
  • Validate - To send and receive messages perform below steps in Azure Portal and in Cloud Shell as mentioned below:

    • Go to Azure Portal and navigate to created Service Bus namespace.

    • Select myQueue option at bottom of Overview window.

      Overview Page
    • Click on Service Bus Explorer from left navigation panel.

    • Select Peek from start and four messages will appear within few seconds.

    • Now go to Cloud Shell and press any key to continue and application will process four messages.

    • Return back to Azure Portal once application had completed the processing of messages.

    • Select Peek from start again and there will be no messages in queue.

Clean up resources

Once finished the exercise its recommended to delete cloud resources are being created to avoid the unnecessary resource usage and any future costs. Deleting a resource group will delete all resources contained within it. Perform following steps one by one into Azure Portal to achieve this:

  • Navigate to resource group which is being created here and view its contents.

  • Delete resource group selection from the toolbar.

  • Choose resource group name and then follow next directions to delete resource group and all the resources it contains.

One can also clean up resources using Azure CLI as following:

  • Delete role assignment - az role assignment delete command is used to remove role assignments.

az role assignment delete\
     --role "Azure Service Bus Data Owner" \
     --scope $resourceID
  • Delete queue - az servicebus queue delete command is used to remove a queue from specified namespace.

az servicebus queue delete \
     --name myQueue \
     --resource-group $resourceGroup \
     --namespace-group $namespaceName\
  • Delete namespace - az servicebus namespace delete command is used to delete an existing namespace. It removes all associated resources under a namespace.

az servicebus namespace delete \
     --name $namespaceName\
     --resource-group $resourceGroup
  • Delete resource group - az group delete command is used to remove resource group.

az group delete \
     --name myResourceGroup1

Summary

Here, a complete process flow is described to send and receive messages from Azure Service Bus using .NET Client Library. Azure Service Bus resource is created using Azure CLI and assigned “Azure Service Bus Data Owner” role to Microsoft Entra (Azure AD) username. A .NET console application is developed using Azure.Messaging.ServiceBus SDK to send and receive messages. Finally, resources are cleaned up. A complete code of Program.cs file is attached with this article.