"Knowledge has to be improved, challenged, and increased constantly, or it vanishes."

Running background tasks in ASP.Net applications

While developing applications, you may come across various occasions where you create background services to achieve automation in your applications. Such services include sending notification, update a user’s subscription expiration or may be changing the state of a workflow activity and so on.

Developers use Windows Service, Cron jobs or Executables that works in a separate thread than your web applications that works based on a schedule. In .Net, for creating a background task, developers mainly use the Console Application or Windows Service template. While this will do the job, it adds some complexity. Few of the issues developers face with background services are below

  • You may use configuration files in the web application such as connection string, logs file path etc, however for the console application, you need to redefine them under its application settings, something your operation team will not prefer, of course this adds operations complexity.
  • Migrating the application may lead to troubles as I have seen several times, the migration happens without migrating the background service and then developers troubleshoot and identifies they forgot some of the services.
  • Modifying the code in the application and database structure may impact the background service.
  • And many more


Though it had limitations, developers used it a lot especially when they need to implement background services. Now with the ASP.Net framework has built in capability to run background tasks from the web application itself. Cool, for many of you, it must be music to your ears, now from the same project you can manage your pages, application logic and background services.

Background Service in Asp.Net application

In ASP.Net background tasks can be implemented as hosted services. In this article, I am going to demonstrate how you can develop a background service in ASP.Net

For the purpose of this demo, I used the following environment.

    • ASP.Net 6
    • Visual Studio 2022 Preview
    • ASP.Net Web application


Also, I have a class in my application called Task that has a due date and Is Completed flag. I have a page that create a task by setting a due date. Now I am going to create a background service in ASP.Net application itself that set IsCompleted to true for tasks when it reaches the due date.

See the Task class below.

public class Task { public int Id { get; set; } public string Title { get; set; } public DateTime DueDate { get; set; } public bool IsCompleted { get; set; } public DateTime ActionDate { get; set; } }

I created a CreateTask Page, that create a task by entering a title and date with time.

clip_image002

Let me add 10 tasks each varies its due date by 5 minutes. By default, the IsCompleted property is set to false and Action Date is null. Both these fields will be updated by the background service.


clip_image004

Background Service

A Background service can be created by inheriting your class from BackgroundService class

public class MyBackgroundService : BackgroundService

You need to implement the ExecuteAsync method and write your code. Before diving deep into the ExecuteAsync method, let us discuss about accessing scoped services from the background service. For e.g. you may need to access the ApplicationDbContext. For you to use scoped services, you need to create the scope. Let me show you how you can do that.

First you create a read-only property for the Interface IServiceScopeFactory in your background service class

public readonly IServiceScopeFactory ScopeFactory;

use Dependency Injection to get the scope factory instance in the constructor.

public MyBackgroundService(IServiceScopeFactory scopeFactory)
{
    ScopeFactory = scopeFactory;
}

Now whenever you need a scoped service, just get it as below.


using (var scope = ScopeFactory.CreateScope())
{
    var service = scope.ServiceProvider.GetRequiredService<ScopedService>();
}

For example, the following code will get the ApplicationDbContext

using (var scope = ScopeFactory.CreateScope())
{
    var db = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
}

Once you have the services, you can use them in the ExecuteAsync method. Find the ExecuteAsync method that was written to update the Task status.

protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
    while (!stoppingToken.IsCancellationRequested)
    {
        using (var scope = ScopeFactory.CreateScope())
        {
            var db = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
            foreach(var pendingTask in db.Tasks.Where(t=>!t.IsCompleted && t.DueDate<DateTime.Now))
            {
                pendingTask.ActionDate = DateTime.Now;
                pendingTask.IsCompleted = true;
            }
            db.SaveChanges();
         }
         await Task.Delay(TimeSpan.FromMinutes(5));
     }
}

The ExecutiveAsync method will be running indefinitely by using a loop. The Task.Delay is implemented to release the thread and the code will be resumed after the delay minutes.

The above code is simple, when the code executes, it fetches all tasks from the database and update its IsCompleted property to true, if it’s duedate is passed.

Once you are done with the background service, you need to register it. In the Program.cs (.Net 6) or in startup.cs (in prior versions) you can register it with the AddHostedService method.

builder.Services.AddHostedService<MyBackgroundService>();

SNAGHTML517ef40

Now let us run the application and wait for some time.

clip_image006

You may observe that every 5 minutes difference, the tasks are getting updated. The reason is that I used Delay with 5 minutes, you may use your own logic here in ExecuteAsync and easily integrate background services to your ASP.Net applications.

Summary

Though the above example is too simple, it demonstrates the basic stuffs. You may have your own application logic where you can configure properties such as delays. Also you can have multiple types of synchronization, for e.g. you may have user expiry notifications once in a day and you may work with workflow tasks activity updates every 5 minutes.

Happy Programming!

References:

https://docs.microsoft.com/en-us/aspnet/core/fundamentals/host/hosted-services?view=aspnetcore-5.0&tabs=visual-studio

https://docs.microsoft.com/en-us/dotnet/architecture/microservices/multi-container-microservice-net-applications/background-tasks-with-ihostedservice

10 Comments

Add a Comment

As it will appear on the website

Not displayed

Your website