How to create a .NET8 WebAPI for receiving messages from Azure ServiceBus

See the source code for this demo in this github repo: https://github.com/luiscoco/Azure_ServiceBus_with_dotNET8_WebAPI_consumer

1. Create Azure ServiceBus (Topic and Subscrition)

We first log in to Azure Portal and search for Azure Service Bus

image

We create a new Azure Service Bus

image

We input the required data: Subscription, ResourceGroup, Namespace, location and pricing tier

image

We verify the new Azure Service Bus

image

We get the connection string

image

image

This is the connection string:

Endpoint=sb://myservicebus1974.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=c/7ve5kw9QuPqM8YSUWQvNTrjM+y5hkmp+ASbE85qY4=

We have to create a new topic

image

We also have to create a new subscription

image

image

2. Create a .NET8 WebAPI with VSCode

Creating a .NET 8 Web API using Visual Studio Code (VSCode) and the .NET CLI is a straightforward process

This guide assumes you have .NET 8 SDK, VSCode, and the C# extension for VSCode installed. If not, you'll need to install these first

Step 1: Install .NET 8 SDK

Ensure you have the .NET 8 SDK installed on your machine: https://dotnet.microsoft.com/es-es/download/dotnet/8.0

You can check your installed .NET versions by opening a terminal and running:

dotnet --list-sdks

If you don't have .NET 8 SDK installed, download and install it from the official .NET download page

Step 2: Create a New Web API Project

Open a terminal or command prompt

Navigate to the directory where you want to create your new project

Run the following command to create a new Web API project:

dotnet new webapi -n ServiceBusReceiverApi

This command creates a new directory with the project name, sets up a basic Web API project structure, and restores any necessary packages

Step 3: Open the Project in VSCode

Once the project is created, you can open it in VSCode by navigating into the project directory and running:

code .

This command opens VSCode in the current directory, where . represents the current directory

3. Load project dependencies

We run this command to add the Azure Service Bus library

dotnet add package Azure.Messaging.ServiceBus

We also have to add the Swagger and OpenAPI libraries to access the API Docs

This is the csproj file including the project dependencies

image

4. Create the project structure

image

5. Create the Controller

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Azure.Messaging.ServiceBus;
using Microsoft.AspNetCore.Mvc;

namespace ServiceBusReceiverApi.Controllers
{
    public class MessageDto
    {
        public string? Body { get; set; }
        public string? Priority { get; set; }
    }

    [ApiController]
    [Route("api/[controller]")]
    public class ServiceBusController : ControllerBase
    {
        private static string connectionString = "Endpoint=sb://myservicebus1974.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=c/7ve5kw9QuPqM8YSUWQvNTrjM+y5hkmp+ASbE85qY4=";
        private static string topicName = "mytopic";
        private static string subscriptionName = "mysubscription";
        private static ServiceBusClient client;
        private static ServiceBusProcessor processor;
        private static ConcurrentQueue<MessageDto> receivedMessages = new ConcurrentQueue<MessageDto>();

        static ServiceBusController()
        {
            client = new ServiceBusClient(connectionString);

            var processorOptions = new ServiceBusProcessorOptions
            {
                AutoCompleteMessages = true
            };

            processor = client.CreateProcessor(topicName, subscriptionName, processorOptions);
            processor.ProcessMessageAsync += MessageHandler;
            processor.ProcessErrorAsync += ErrorHandler; // Add error handler
        }

        public static async Task StartMessageProcessing()
        {
            await processor.StartProcessingAsync();
        }

        [HttpGet("receive")]
        public ActionResult<IEnumerable<MessageDto>> ReceiveMessages(string? priority = null)
        {
            if (string.IsNullOrEmpty(priority))
            {
                return receivedMessages.ToList();
            }
            else
            {
                return receivedMessages.Where(m => m.Priority == priority).ToList();
            }
        }

        static async Task MessageHandler(ProcessMessageEventArgs args)
        {
            string body = args.Message.Body.ToString();
            string priority = args.Message.ApplicationProperties["priority"]?.ToString() ?? "normal";
            Console.WriteLine($"Received message: {body}, Priority: {priority}");

            receivedMessages.Enqueue(new MessageDto { Body = body, Priority = priority });

            await Task.CompletedTask;
        }

        static async Task ErrorHandler(ProcessErrorEventArgs args)
        {
            Console.WriteLine($"Error source: {args.ErrorSource}");
            Console.WriteLine($"Fully qualified namespace: {args.FullyQualifiedNamespace}");
            Console.WriteLine($"Entity path: {args.EntityPath}");
            Console.WriteLine($"Exception: {args.Exception.Message}");

            await Task.CompletedTask;
        }
    }
}

6. Modify the application middleware(program.cs)

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.OpenApi.Models;
using ServiceBusReceiverApi.Controllers;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddControllers();

// Add Swagger
builder.Services.AddSwaggerGen(c =>
{
    c.SwaggerDoc("v1", new OpenApiInfo { Title = "ServiceBusReceiverApi", Version = "v1" });
});

var app = builder.Build();

// Configure the HTTP request pipeline.
app.UseRouting();

// Enable middleware to serve generated Swagger as a JSON endpoint.
app.UseSwagger();

// Enable middleware to serve swagger-ui (HTML, JS, CSS, etc.), specifying the Swagger JSON endpoint.
app.UseSwaggerUI(c =>
{
    c.SwaggerEndpoint("/swagger/v1/swagger.json", "ServiceBusReceiverApi v1");
});

app.UseAuthorization();

app.MapControllers();

// Start message processing
ServiceBusController.StartMessageProcessing().Wait();

app.Run();

7. Run and Test the application

We execute this command to run the application

dotnet run

We receive in the VSCode console the messages from Azure Service Bus

image

We can also see the messages received in Swagger: http://localhost:5221/swagger/index.html

image