Building an Asp.Net Core Windows Service Task Scheduler

Create zip files and upload to the Azure blob storage daily, weekly, or monthly using Quartz with DI

Sibeesh Venu
Aug 12 · 7 min read
Windows Service Log

Introduction

Windows services are a good way to reduce some manual jobs that we have to do in our system. In this piece, we are going to write a Windows service using Asp.Net core. The jobs tasked to this Windows service is as follows:

  1. Zip the folder and save the file to a particular directory
  2. Upload the zipped folder to the Azure blob storage

The above-mentioned tasks will be running daily, weekly, or monthly. We are using the Quartz scheduler with Dependency Injection to do these amazing tasks. We are using Nlog to log the details of our tasks. If this interests you, then you are in the right place. Let’s develop our PerfectScheduler.


Source Code

The source code of this project has been uploaded to GitHub. Please feel free to fork, star, create pull requests, etc. The repository can be found here.


Creating Our Perfect Scheduler

As I mentioned earlier, we are creating a Windows service with Asp.Net core. Technically there is no straight way to do this, as the Windows service with Asp.Net core template is not available in Visual Studio.

No Windows Service Project Template

So we will be creating an Asp.Net console application and then installing an executable file generated as a Windows service.

.Net Core Console Application

Creating an Asp.Net Console Application

Open Visual Studio, search for the project template Console App (.Net Core), and name the solution as per your convenience. I am naming this project Perfect Scheduler, as I am thinking that we can make this Windows service perfect by creating many pull requests.

Once you have created the application, install all of our dependencies so that we don’t need to worry about them later.

Asp.Net Core Windows Service Dependencies

Write the Service

As we have installed all of our dependencies, we are ready to create our service. Add a new class with the name BackupService and inherit the same from IHostedService, which is part of Microsoft.Extensions.Hosting namespace.

IHostedService has two methods in it as follows, so we should implement them in our service class:

IHostedService

The StartAsync method can be implemented as follows:

StartAsync

As you can see in the first line of the above code, we are getting the scheduler of Quartz. Let’s create a method and return a scheduler:

GetScheduler

The next step is to build a service provider so that we can inject our dependencies using Constructor Dependency Injection. By default Quartz is not doing this, so we have to build the configuration our own.

GetConfiguredServiceProvider

As you can see, we have configured the services for DailyJob, WeeklyJob, MonthlyJob, and HelperService. We will be creating these Classes and Interfaces very soon.

Once we get the Service Provider, we can pass this to our Custom Job Factory, which we will be implementing soon. Now, we can start the scheduler and schedule our jobs, please make sure that you are using different Identity names for both Triggers and Jobs. The samples are given below:

Jobs And Triggers

The StopAsync method can be implemented as follows:

Stop Async

Creating the JobBuilders and TriggerBuilders

Now we can create the Interfaces and Classes for our Jobs, which are Daily, Weekly, and Monthly. To do so, create a new folder called Helpers and another folder called Interfaces inside. Below are the Interfaces you need to create.

IDailyJob
IWeeklyJob
IMonthlyJob
IHelperService

Create a Custom Job Factory

To implement the Dependency Injection, we need to create our own custom job factory. Create a class inside the Helper folder as follows:

Custom Job Factory

Implement the Job Builder Interfaces

Now it is time to implement our Daily, Weekly, and Monthly job builders.

DailyJob
WeeklyJob
MonthlyJob

We have configured separate classes for each of the jobs with the dependency IHelperService injected via constructor. In the future, we should be able to write custom logic for each job here as they are in separate classes.


Implement HelperService

Before we start implementing this service let us configure the NLog now as we will be writing logs from this class.

To configure NLog, create a new configuration file NLog.config and edit the content as shown:

NLog.config

Now, create a method SetUpNLog() and add the codes as below:

SetUpNLog

Please make sure that you have already added a property ILogger _logger.

We can implement the HelperService as follows with all the necessary private and public methods:

HelperService

The method PerformService (string schedule) will be called for every schedule and it will make sure that the below tasks are performed.

  1. Zip the folder and save the file to a particular directory
  2. Upload the zipped file to the Azure blob storage

Here, the values of the variable and the blob storage container names are the same, either daily, weekly, or monthly. If you are not sure how to upload a blob to Azure storage account, I strongly recommend you read my article here.

Remember to set the values for the FolderToZipLocation (where the location the file should be saved), FolderFromZipLocation (from where the files should be taken), and StorageConnectionString in the App.config file.

App.config

Setting Up The Program

As you know, the Program class is the start of our console application, now it is time to call our BackupService from the Program class. Let us edit the code of the Program class seen below:

Program

If we are running the application locally/debug, we are calling the extension method RunConsoleAsync() or else we call our own custom extension method RunTheServiceAsync(). The line services.AddHostedService() is very important as this is where we register our IHostedService, which is BackupService. Below is the code for our extension method:

ServiceBaseLifetimeExtension

The ServiceLifetime class is where we override the methods from the ServiceBase class. The implementation is as follows:

ServiceLifeTime

Creating the Windows Service

As we have already created the Asp.Net Core console application, now it is time to create a windows service from it. Make sure that you had set the RuntimeIdentifier to win7-x64 and SelfContained to true in the properties of your project, this will make sure that all of your dependencies are being added to your executable file so that you don’t need to worry about handling your dependencies manually. You can read more about it here. To do so, right click on the project and click on Edit Project File. In the end, your csproj file should be similar to:

Backup.Service.csproj

Create the Release Configuration

You should also run the dotnet publish command with the release configuration before you try to install the service, because you need this executable file to install the service.

Open the command prompt with administrator privilege and go to the project root folder using the cd command. Run the command dotnet publish --configuration=release.

This will generate everything you wanted. If you run the command correctly, you should see this output:

Dotnet Publish Release

Now go to the bin folder and then release folder, you should see a folder with the name netcoreapp2.1. Inside the folder, there will be a folder named win7-x64, this is the folder where your .exe file, log file, and other items reside.


Install the Service

To install our Asp.Net console application as a Windows service, you can use the sc command. Open the command prompt with administrator privilege and run the command:

SC Create With Delayed Start

And then you can start the service by running the command as sc start BackupService. This should start your service.


Giving Permission to the Folders

Sometimes you may get a permission issue in your service as it doesn’t have enough permission to read the files from the C drive. To overcome this, you should give enough permission to the user. You can do this by editing the security properties of those folders.

Setting Permission for the Users

Do the same for the BackupZip folder as well.


Output

If you run the service correctly, you should see a log file with the name backupclientlogfile.txt inside your win7-x64 folder. Once the service is run, the logs will be written as follows.

Perfect Scheduler Output

You can also check your Azure Storage account to check whether the files have uploaded correctly or not.


Conclusion

Wow! We have learned:

  • About Windows Service and Asp.Net Console Application
  • About how to create a Windows Service using Asp.Net Core
  • About how to use Quartz scheduler
  • About how to use NLog in Windows Service
  • About how to configure Quartz scheduler to use Dependency Injection
  • About how to Zip a folder and save the file
  • About how to upload a file to the Azure blob storage

Your Turn. What Do You Think?

Thanks a lot for reading. Did I miss anything that you may think which is needed in this article? Did you find this post as useful? Don’t forget to share your thoughts with me in the comments!

Kindest Regards
Sibeesh Venu

Better Programming

Advice for programmers.

Sibeesh Venu

Written by

An #Engineer by profession and #Writer by passion. Microsoft MVP. sibeeshpassion.com, youtube.com/sibeeshPassion, youtube.com/njanorumalayali

Better Programming

Advice for programmers.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade