Getting Started with Azure Service Bus Queues & ASP.NET Core - Part 2
Tags: azure, dotnet, serverless, csharp
Published: 2020-12-17 16:36:28

In this article, we are going to discuss about how to listen message from Azure Service Bus Queues. In the Part 1 we have discussed about  Azure Service Bus Queues and how to send message into Queues using ASP.NET Core Web API. Please read part 1 before starting this article.

{% link https://dev.to/sumitkharche/get-started-with-azure-service-bus-queues-asp-net-core-part-1-255l %}

## Creating a simple application to send and receive messages from the queue.

#### Prerequisites
* [Azure](https://portal.azure.com) account(If you don't have an Azure subscription, [create a free trial account](https://azure.microsoft.com/free).)
* Basic knowledge of Asp.net Core Web API

#### Overview of application
In Part 1, we have created a Azure Service Bus Queue from Azure Portal and also created ASP.NET Core Web API to push message  into that queue:

![App Structure](https://dev-to-uploads.s3.amazonaws.com/i/h6v77l1g5vu74ijwcahz.png)

In this article, we are going to create a Background Service to receive a message from Queue. 

We will be using same service bus (**order-test-asb**) and queue (**order-queue**) that we created in Part 1 for this article.

![queue-message](https://dev-to-uploads.s3.amazonaws.com/i/nrg8ilmx8804l9tkkrnt.PNG)


## Create Background service to listen the message from the Queue

#### *Prerequisites*
* Visual Studio 19(if you are using .NET Core 3.1)
* .NET Core 3.1 SDK installed

According to the [docs](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/host/hosted-services?view=aspnetcore-3.1&tabs=visual-studio):
>
In ASP.NET Core, background tasks can be implemented as hosted services. A hosted service is a class with background task logic that implements the IHostedService interface. This topic provides three hosted service examples:
* Background task that runs on a timer.
* Hosted service that activates a scoped service. The scoped service can use dependency injection (DI).
* Queued background tasks that run sequentially.

Along with IHostedService we have BackgroundService class is first introduced in ASP.NET Core 3.0 and which is an abstract class that already implements the IHostedService Interface. BackgroundService also gives an abstract method ExecuteAsync() that returns a Task. So in this article we are inheriting our class with BackgroundService and implements an ExecuteAsync() method.

In part 1 we have created `Order.Web.Api` which is used to send a message into service bus. Now we are going to create a hosted background service which is continuously running and listening a service bus messages. 

* Go to solution and right click on it and select **Add** and select **New Project**.
* Select Console App(.Net Core) and click on Next.
![add-new-project-1](https://dev-to-uploads.s3.amazonaws.com/i/ls8j6dch5c0o3bbxck8i.PNG)
* Give name to service and click on Create.
![add-new-project-2](https://dev-to-uploads.s3.amazonaws.com/i/w1yopvo3pi8qbwxcgc51.PNG)
* Create a new file called `appsettings.json` & add azure service connection string as below:
```json
{
 "AppSettings": { 
   "QueueConnectionString": "<replace your RootManageSharedAccessKey here>",
   "QueueName": "order-queue"
 }
}
```
* First we have to install Azure Service Bus NuGet package:
![azure-servicebus-nuget-details](https://dev-to-uploads.s3.amazonaws.com/i/oo951gbl7e6abaekv2ca.PNG)
* So this service needs to listen messages from Azure Service bus we can create this as Windows service. Along with that add below code to read to the Appsettings from `appsettings.json`. So create a class called AppSettings.cs as mentioned below:
```csharp
    public class AppSettings
    {
        public string QueueConnectionString { get; set; }
        public string QueueName { get; set; }
    }
```
* To configure our service first we need to install below packages:
![dependency-nuget](https://dev-to-uploads.s3.amazonaws.com/i/aob9sd0ey4tb6tdfe7ph.PNG)
![hosting-nuget](https://dev-to-uploads.s3.amazonaws.com/i/iohcj82u40njulz12btz.PNG)
![windows-service-nuget](https://dev-to-uploads.s3.amazonaws.com/i/fmvicy8fv2oowwi4xzfl.PNG)

* After that add below code in `program.cs` to configure our service:
```csharp
      class Program
    {
        static void Main(string[] args)
        {
            IServiceCollection serviceDescriptors = new ServiceCollection();
             Host.CreateDefaultBuilder(args)
                .UseWindowsService()
                .ConfigureHostConfiguration(configHost =>
                {
                    configHost.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true).Build();
                })
                .ConfigureServices((hostContext, services) =>
                {
                    var appSettingsConfig = hostContext.Configuration.GetSection(nameof(AppSettings));

                    services.AddOptions();
                    services.Configure<AppSettings>(appSettingsConfig);
                    services.AddSingleton(appSettingsConfig);
                }).Build().Run();
        }
    }
```
* Now next part is to create Background service to listen messages. So create a class called CraeteOrderHandler.cs and inherits it with class `BackgroundService`. Now override the `ExecuteAsync` and `StopAsync` method of BackgroundService class.
```csharp
using System;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Azure.ServiceBus;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;

namespace OrderService
{
    public class CraeteOrderHandler : BackgroundService
    {
        private readonly AppSettings _appSettings;
        private IQueueClient _orderQueueClient;

        public CraeteOrderHandler(IOptions<AppSettings> appSettings)
        {
            _appSettings = appSettings?.Value ?? throw new ArgumentNullException(nameof(appSettings));
        }

        public async Task Handle(Message message, CancellationToken cancelToken)
        {
            if (message == null)
                throw new ArgumentNullException(nameof(message));

            var body = Encoding.UTF8.GetString(message.Body);
            Console.WriteLine($"Create Order Details are: {body}");
            await _orderQueueClient.CompleteAsync(message.SystemProperties.LockToken).ConfigureAwait(false);
        }
        public virtual Task HandleFailureMessage(ExceptionReceivedEventArgs exceptionReceivedEventArgs)
        {
            if (exceptionReceivedEventArgs == null)
                throw new ArgumentNullException(nameof(exceptionReceivedEventArgs));
            return Task.CompletedTask;
        }

        protected override Task ExecuteAsync(CancellationToken stoppingToken)
        {
            var messageHandlerOptions = new MessageHandlerOptions(HandleFailureMessage)
            {
                MaxConcurrentCalls = 5,
                AutoComplete = false,
                MaxAutoRenewDuration = TimeSpan.FromMinutes(10)
            };
            _orderQueueClient = new QueueClient(_appSettings.QueueConnectionString, _appSettings.QueueName);
            _orderQueueClient.RegisterMessageHandler(Handle, messageHandlerOptions);
            Console.WriteLine($"{nameof(CraeteOrderHandler)} service has started.");
            return Task.CompletedTask;
        }

        public override async Task StopAsync(CancellationToken stoppingToken)
        {
            Console.WriteLine($"{nameof(CraeteOrderHandler)} service has stopped.");
            await _orderQueueClient.CloseAsync().ConfigureAwait(false);
        }

    }
}

```
* In ExecuteAsync() method calls when service is starts so we have setup a queue client object and also register Handle method to listen messages.
* In StopAsync() method we close the queue client connection.
* In Handle() method we just extract body from messasge which contains our actual data and just print it in console.
* After that let's register our hosted service by adding below line into `ConfigureServices` method in Program.cs class.
```csharp
services.AddHostedService<CraeteOrderHandler>();
```
* So lets build and run the service to listen messages. Start order web api and send message to queue which our OrderService going to be listen.
![send-message-using-web-api-postman](https://dev-to-uploads.s3.amazonaws.com/i/q00su4cnkp4sdtiaymvj.PNG)
![listen-message-console-log](https://dev-to-uploads.s3.amazonaws.com/i/wj0vezv82bwg9g4p2jbc.PNG)

  
# Conclusion

In this article of Azure Service Bus Queue series, We have learned and implemented Background Service to listen message from azure service bus queue.

I really hope that you enjoyed this article, share it with friends and please do not hesitate to send me your thoughts or comments.

You can follow me on twitter [@sumitkharche01](https://twitter.com/sumitkharche01) or [LinkedIn](https://www.linkedin.com/in/sumit-kharche-890426a9)

Happy Coding!!