Multiple Background Services in a.NET Core Web App with periodic runs

We will look at how to create a.NET Core web application using background services in this blog article. Background services are perfect for jobs like scheduling, monitoring, and other asynchronous operations since they are long-running processes that operate separately from the main application thread. In particular, we’ll concentrate on developing InstrumentationService and PeriodicService, two background services.

While the PeriodicService will run on a customizable interval, the InstrumentationService will run continually.

Establishing the Project

To begin, let’s make a brand-new.NET Core web application project. Enter the following command into your terminal or command prompt window:

dotnet new web -n BackgroundServicesDemo
cd BackgroundServicesDemo

This command creates a new .NET Core web application project named BackgroundServicesDemo. Navigate into the project directory.

Add appSettings.json modifications

"PeriodicServiceSettings": {
  "IntervalInMinutes": 5
}

Creating Background Services

Now, let’s create the background services. We’ll start by creating the InstrumentationService class, which will continuously log information.

using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using System;
using System.Threading;
using System.Threading.Tasks;

public class InstrumentationService : IHostedService, IDisposable
{
    private readonly ILogger<InstrumentationService> _logger;
    private Timer _timer;

    public bool IsRunning { get; private set; }

    public InstrumentationService(ILogger<InstrumentationService> logger)
    {
        _logger = logger;
    }

    public Task StartAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("Instrumentation Service is starting.- {0}", DateTime.Now);
        _timer = new Timer(DoWork, null, TimeSpan.Zero, TimeSpan.Zero); // Adjust delay as needed
        IsRunning = true;
        return Task.CompletedTask;
    }

    private void DoWork(object state)
    {
        _logger.LogInformation("Instrumentation Service is running.");
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("Instrumentation Service is stopping.- {0}", DateTime.Now);
        _timer?.Change(Timeout.Infinite, 0);
        IsRunning = false;
        return Task.CompletedTask;
    }

    public void Dispose()
    {
        _timer?.Dispose();
    }
}

Next, let’s create the PeriodicService class, which will run periodically based on a configurable interval.

public class PeriodicService : BackgroundService
{
    private readonly ILogger<PeriodicService> _logger;
    private readonly IConfiguration _configuration;
    private readonly InstrumentationService _instrumentationService;
    private bool _isRunning;
    public PeriodicService(
        ILogger<PeriodicService> logger,
        IConfiguration configuration,
        InstrumentationService instrumentationService)
    {
        _logger = logger;
        _configuration = configuration;
        _instrumentationService = instrumentationService;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        var intervalInMinutes = _configuration.GetValue<int>("PeriodicServiceSettings:IntervalInMinutes");

        while (!stoppingToken.IsCancellationRequested)
        {
            _logger.LogInformation("Periodic Service is running. - {0}", DateTime.Now);

            // Stop Instrumentation Service
            _logger.LogInformation("Stopping Instrumentation Service... - {0}", DateTime.Now);
            await StopInstrumentationService();

            // Do Periodic Service Work
            await Task.Delay(TimeSpan.FromMinutes(1), stoppingToken); // Simulated work
            _logger.LogInformation("Periodic Service work is done. - {0}", DateTime.Now);

            // Restart Instrumentation Service
            _logger.LogInformation("Restarting Instrumentation Service... - {0}", DateTime.Now);
            await StartInstrumentationService();

            // Wait for next interval
            await Task.Delay(TimeSpan.FromMinutes(intervalInMinutes), stoppingToken);
        }
    }

    private async Task StartInstrumentationService()
    {
        if (InstrumentationServiceIsRunning())
            return;

        await _instrumentationService.StartAsync(CancellationToken.None);
    }

    private async Task StopInstrumentationService()
    {
        if (!InstrumentationServiceIsRunning())
            return;

        await _instrumentationService.StopAsync(CancellationToken.None);
    }

    private bool InstrumentationServiceIsRunning()
    {
        return _instrumentationService.IsRunning; // Placeholder, replace with actual logic
    }
}

Registering Background Services

Now, let’s register the background services in the dependency injection container. Open the Program.cs file and update the Main method as follows:

public class Program
{
    public static async Task Main(string[] args)
    {
        var builder = WebApplication.CreateBuilder(args);

        // Add services to the container.
        builder.Services.AddHostedService<InstrumentationService>(); // Register InstrumentationService
        builder.Services.AddHostedService<PeriodicService>(); // Register PeriodicService
        builder.Services.AddLogging(); // Add logging
        // Register InstrumentationService as a singleton
        builder.Services.AddSingleton<InstrumentationService>();
        await using var app = builder.Build();

        // Configure the HTTP request pipeline.
        app.MapGet("/", () => "Hello World!");

        await app.RunAsync();
    }
}

With this setup, the InstrumentationService will run continuously, and the PeriodicService will run periodically based on the configured interval.

Conclusion

In this blog post, we explored how to build a .NET Core web application with background services. We created two background services: InstrumentationService and PeriodicService, and registered them in the dependency injection container. Background services are a powerful feature of .NET Core, enabling developers to perform asynchronous tasks efficiently.

Best and Most Recommended ASP.NET Core 8 Hosting

Fortunately, there are a number of dependable and recommended web hosts available that can help you gain control of your website’s performance and improve your ASP.NET Core 8 web ranking. HostForLIFEASP.NET is highly recommended. In Europe, HostForLIFEASP.NET is the most popular option for first-time web hosts searching for an affordable plan.

Their standard price begins at only € 3.49 per month. Customers are permitted to choose quarterly and annual plans based on their preferences. HostForLIFEASP.NET guarantees “No Hidden Fees” and an industry-leading ’30 Days Cash Back’ policy. Customers who terminate their service within the first thirty days are eligible for a full refund.

By providing reseller hosting accounts, HostForLIFEASP.NET also gives its consumers the chance to generate income. You can purchase their reseller hosting account, host an unlimited number of websites on it, and even sell some of your hosting space to others. This is one of the most effective methods for making money online. They will take care of all your customers’ hosting needs, so you do not need to fret about hosting-related matters.