In the previous chapter, we discussed the enterprise Azure Service Bus and its key features. We explored ways to provision a service bus instance in the Microsoft Azure portal and interact with a service bus queue using our ASP.NET Core web application. You learned about ways to send as schedule a message to the service bus queue. In this chapter, we will build upon the knowledge gained from the previous chapter and explore ways to receive and process messages from the service bus queue.
We will be exploring ways to process messages from the service bus queue by building a .NET Core Worker Service for our fictional dental clinic to send email alerts for the scheduled appointment notifications to the clinic’s patients. The solution will be able to process the enqueued messages in the service bus queue and send an email alert to a patient to remind them about their scheduled appointment at our fictional dental clinic.
Structure
Introduction to worker services
Build a .NET Core worker service to process messages to Azure Service Bus Queue
Deploy the worker service to Azure WebJobs
Objectives
Understand the fundamentals of worker services
Deploy worker services to Azure WebJobs
Introduction to .NET Core Worker Services
Often, we come across scenarios where we would like to perform certain operations which can or cannot be memory intensive by our applications. Many times these operations don’t require a user interface (UI) and are run as background services that run on a schedule or perform operations continuously. Some examples of such example can be to generate reports and send email alerts to the end users periodically or process messages from a message queue. These kinds of scenarios can be handled using background services that run either 24×7 or periodically to perform business requirements.
Along with ASP.NET Core 3.0, a new application template was introduced, the Worker Service template. This template allows us to create an out-of-the-box project to create background services with .NET Core with some boilerplate code. We can create cross-platform background services with the Worker Service template, which can be configured to run as Windows services or Linux daemons. These services can be configured to run and execute the business logic periodically over time or continuously as per the requirement.
Long-running processes
CPU-intensive operations
Performing scheduled tasks
Processing messages asynchronously
Now that we have covered what the Worker Service template is and its use cases, we will explore the life-cycle methods of worker services.
Life-Cycle Methods of Worker Services
Worker classes are added as hosted services using the AddHostedService method in the program.cs class. A worker class implements the BackgroundService abstract class and the BackgroundService class implements the IHostedService interface. Any functionality that we want our worker class to perform needs to be implemented inside the ExecuteAsync method. This method is an abstract method present in the BackgroundService abstract class that is implemented by the worker class.
Apart from ExecuteAsync, there are two other methods, StartAsync and StopAsync, that can be overridden by a worker service to explicitly handle scenarios where we are concerned about activities that need to be performed at the start or end of the worker service. The BackgroundService class provides an implementation of StartAsync and StopAsync methods by default, but we can always override them as per the requirement in our respective worker class.
Problem Statement
As discussed in the previous chapter, our fictional dental clinic wants to send notifications to its customers to remind them about their upcoming appointments. As part of the work performed in the previous chapter, we are able to schedule messages in our service bus queue. But so far, we haven’t been able to do anything with the messages scheduled in the service queue. We need to send email alerts to the patients of our fictional dental clinic about their scheduled appointments to solve the problem statement.
Proposed Solution
Now that you have a brief understanding of background services and have the problem statement at hand, we will be working toward designing and developing a solution to complete the requirements of our fictional dental clinic. We have completed the part of scheduling the appointments in a service bus queue in the previous chapter, but we have yet to find a solution to process these appointments scheduled as messages in the queue. There are various ways we can process the messages, like using a background service or a function app. That solves one part of our requirement, which is to process messages. Now we need to solve one more puzzle: How do we send email notifications to the patients? Well, we have many solutions available to solve this problem. We can use the Gmail SMTP server or use third-party services like SendGrid to send emails to the clinic’s patients.
As we have found quite a few options to solve our problem statement, let’s walk through the approach that we have decided to use to solve the problem statement. We plan to build a background service using the Worker Service template, which will poll for messages continuously and send email alerts to customers using the Gmail SMTP server. We will later deploy this background service to an Azure WebJob and test the functionality by sending a message to the service bus queue by using the Service Bus Explorer in the Azure portal.
Create a Listener SAS policy in Azure Service Bus Queue
Generate the app password for your Gmail account
Once we have these two things in place, we will start building our background service using the Worker Service template in Visual Studio 2022.
Create an SAS Policy to Access the Azure Service Bus Namespace
As discussed in Chapter 2, to access or interact with Azure Service Bus Queues or Topics from our application, we need to authenticate our application’s request to the service bus. This can be done in different ways, such as using Azure Active Directory (Azure AD)–based authentication or SAS policies. For the purpose of this book, we will be using SAS policies. For enterprise applications, it is recommended to use Azure AD–based authentication or managed identity if the applications are deployed inside Azure in an Azure Function or App Service by providing necessary RBAC permissions to the service bus instance.
Generate an App Password in our GMAIL account
Now that we have the connection string and password necessary to build our background service, we will start developing the solution using the Worker Service template in the next section.
Create a Worker Service to Process Scheduled Messages in Azure Service Bus Queue
In the previous section, you learned about worker services. The focus of this section is to solve the need of a fictional dental clinic to send appointment notifications to its patients by using the Worker Service template. The clinic currently has an API that schedules appointments as messages in the service bus queue. As part of this section, we will build a background service that polls for messages continuously and sends email alerts to the patients about their scheduled appointments.
Now Visual Studio will create a sample Worker Service project for us that will contain a simple worker service that inherits the BackgroundService abstract class and provides an implementation to the ExecuteAsync method, which logs a message every one second.
For the time being, we are done with the program.cs file of our project. Let’s create two folders in our project: Business and Models. The Business folder will contain our interface and the classes implementing them. The Models folder will contain the classes of our data models.
In the preceding code snippet, we are instantiating an instance of the IConfiguration interface to access the values that we earlier stored in our appsetting.json file.
Now let’s implement the methods of the IMailService interface in the class. Let’s add the following code snippet to implement the methods.
The SendEmail takes the appointment object coming in the parameter of the method and then uses the PatientName and PatientEmail properties of the appointment object to send an email notification. We are defining an object of type MailMessage and provide values of required properties for our case i.e., recipient and sender’s email, Subject, Body. We have created a simple HTML template for the email body. You can customize it to be more elegant using CSS. After instantiating the MailMessage instance, we create an SMTP client using the configuration we stored in our appsettings.json file to send out emails to the patients of our fictional dental clinic
Fetch messages from the service bus queue using the service bus receiver client
Deserialize the content of the message coming from the service bus queue
Make a call to the SendEmail method of the MailService to send an email notification to the patients
And with this our background service to process the scheduled notification for our fictional dental clinic is complete. Press Ctrl+F5 to build and run our project. The complete source code of this background service project can be found at the following GitHub repository: https://github.com/AshirwadSatapathi/QueueProcessor.
In the next section, we will deploy and test our worker service.
Deploy and Test the Worker Service
Now that we have developed our worker service, let’s deploy it to Azure and perform a sanity test. We can deploy a worker service to Azure in multiple ways, like deploying it to a WebJobs or Azure Container Instance or Azure Container Apps. For the purpose of this chapter, we will be using Azure WebJobs, a feature of Azure App Service that allows us to run scripts or programs in the web app instance. WebJobs are used to run background tasks in Azure and are of two types: continuous and triggered.
Continuous WebJobs are used for background tasks that run on an endless loop and start immediately when the WebJob is created. Triggered WebJobs are used for background tasks that need to run when they are triggered manually or are triggered on a scheduled basis. Continuous WebJobs support remote debugging, which is not supported for triggered WebJobs.
Now that you know what Azure WebJobs are, let’s see how we can deploy a worker service to it using Visual Studio.
As you can see, we were able to send an email alert to the patients and solve the problem statement of out fictional dental clinic.
Summary
The Worker Service template provides an out-of-the-box template for building background services in .NET Core. Background services are useful for a variety of scenarios. We can leverage them to build long-running processes to execute continuously or on a scheduled basis. In this chapter, we explored ways to integrate capabilities in our worker service to receive and process messages in our background service by leveraging the powerful Azure Service Bus SDK and used the SMTP client to send email alerts to patients. We saw ways to create a Listener policy in the Azure Service queue and explored ways to create an app password for a Gmail account that can be used to authenticate operations. At the end of the chapter, you learned about ways to deploy our worker service to an Azure WebJob and test it using the Service Bus Explorer provided in the Azure portal for Azure Service Bus Queue.