Background Tasks Using Hosted Services in ASP.NET Core Without Hangfire

Leave a Comment

Sending emails, clearing away old logs, processing files, and updating reports are just a few examples of the background tasks that are frequently required in real-world systems without interfering with user requests.

Many developers immediately turn to frameworks such as Azure Functions, Quartz.NET, or Hangfire.
However, what if you're looking for something integrated directly into ASP.NET Core, lightweight, and dependency-free?

The answer is:
Hosted Services — a powerful built-in feature in ASP.NET Core to run background tasks efficiently.

This article will show you how to build background jobs without Hangfire, step-by-step.

1. What Are Background Jobs?

A background job is any process that runs behind the scenes — not directly triggered by a user and not part of the main request/response flow.

Common Examples
  • Sending order confirmation emails after checkout

  • Generating and emailing PDF reports

  • Cleaning up temporary files

  • Syncing data with third-party APIs at intervals

These tasks can take time, and you don't want them to slow down user requests.
That's where Hosted Services come in.

2. What Are Hosted Services in ASP.NET Core?

ASP.NET Core includes a background task framework out of the box using IHostedService.

You can think of it as a service that starts with your application and runs continuously in the background.

There are mainly two types:

  1. IHostedService – Run logic at startup and shutdown.

  2. BackgroundService – A helper base class for continuous or scheduled jobs.

3. Architecture Overview

Below is a high-level diagram of how Hosted Services work in ASP.NET Core.

Flowchart: Background Job Architecture
+----------------------------------+
| ASP.NET Core Application         |
| (Web API / MVC / Razor / Blazor) |
+-------------------+--------------+
                    |
                    v
+----------------------------------+
| Hosted Service (Background Task) |
| - Runs Independently             |
| - Starts with Application        |
| - Handles Long/Recurring Jobs    |
+-------------------+--------------+
                    |
                    v
+----------------------------------+
| Services / Database / APIs       |
| (Email, File System, Cleanup)    |
+----------------------------------+
4. Step-by-Step Implementation

Let's create a simple background job that runs every 5 minutes and cleans up old logs from the database.

Step 1: Create the Hosted Service Class
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

public class LogCleanupService : BackgroundService
{
    private readonly ILogger<LogCleanupService> _logger;
    private readonly IServiceProvider _serviceProvider;

    public LogCleanupService(ILogger<LogCleanupService> logger, IServiceProvider serviceProvider)
    {
        _logger = logger;
        _serviceProvider = serviceProvider;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        _logger.LogInformation("Log Cleanup Service started.");

        while (!stoppingToken.IsCancellationRequested)
        {
            await DoCleanupAsync();
            await Task.Delay(TimeSpan.FromMinutes(5), stoppingToken); // Runs every 5 minutes
        }

        _logger.LogInformation("Log Cleanup Service stopped.");
    }

    private async Task DoCleanupAsync()
    {
        try
        {
            using (var scope = _serviceProvider.CreateScope())
            {
                var dbContext = scope.ServiceProvider.GetRequiredService<MyAppDbContext>();

                var oldLogs = dbContext.Logs
                    .Where(l => l.CreatedDate < DateTime.UtcNow.AddDays(-30))
                    .ToList();

                dbContext.Logs.RemoveRange(oldLogs);
                await dbContext.SaveChangesAsync();

                _logger.LogInformation($"{oldLogs.Count} old logs cleaned up successfully.");
            }
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error while cleaning up logs.");
        }
    }
}
Step 2: Register the Service in Program.cs
var builder = WebApplication.CreateBuilder(args);

// Register your Hosted Service
builder.Services.AddHostedService<LogCleanupService>();

// Register DbContext and other dependencies
builder.Services.AddDbContext<MyAppDbContext>(options =>
    options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));

var app = builder.Build();

app.MapControllers();
app.Run();

That's it!
Now your background service will automatically start when the application starts.

5. Handling Dependency Injection

When working inside a background service, never directly inject scoped services (like DbContext).
Instead, use IServiceProvider.CreateScope() — as shown above — to create a new service scope.

This ensures clean resource management and prevents memory leaks.

6. Adding Multiple Background Services

You can register multiple hosted services — each handling a different task:

builder.Services.AddHostedService<EmailSenderService>();
builder.Services.AddHostedService<DataSyncService>();
builder.Services.AddHostedService<ReportGeneratorService>();

Each one will run independently in its own background thread.

7. Graceful Shutdown and Cancellation

ASP.NET Core automatically handles graceful shutdowns for hosted services.
When the app stops (or is restarted), it sends a cancellation token (stoppingToken) to stop the job safely.

To handle it cleanly:

if (stoppingToken.IsCancellationRequested)
{
    _logger.LogInformation("Service stopping...");
    break;
}

8. Advanced Scenarios

Scheduled Jobs

You can make jobs run at specific times using Cronos (a lightweight Cron parser):

using Cronos;

private readonly CronExpression _cron = CronExpression.Parse("0 * * * *"); // every hour

Then calculate the next occurrence using:

var next = _cron.GetNextOccurrence(DateTime.UtcNow);

Queue-Based Background Processing

For more complex use cases (like queued background tasks), use BackgroundTaskQueue with Channel or ConcurrentQueue.

9. Benefits of Using Hosted Services

FeatureBenefit
No extra dependencyBuilt directly into .NET Core
LightweightIdeal for microservices and small apps
ReliableStarts/stops with the app lifecycle
FlexibleRun periodic, continuous, or one-time tasks
SecureFull DI and configuration support

10. When Not to Use Hosted Services

  • For long-running or heavy workloads, use Azure Functions, Worker Services, or Hangfire.

  • For distributed job coordination, prefer message queues (RabbitMQ, Kafka).

  • Hosted Services are best for simple, internal background tasks within a single app instance.

Conclusion

You don't always need heavy frameworks like Hangfire for background processing.
ASP.NET Core's Hosted Services provide a clean, native way to manage background jobs — with full integration into dependency injection, logging, and configuration.

They're:

  • Simple to build

  • Reliable to run

  • Perfect for small to medium workloads

By mastering Hosted Services, you gain a powerful tool to run scheduled, continuous, or on-demand background tasks all without adding any external library.

Windows Hosting Recommendation

HostForLIFEASP.NET receives Spotlight standing advantage award for providing recommended, cheap and fast ecommerce Hosting including the latest Magento. From the leading technology company, Microsoft. All the servers are equipped with the newest Windows Server 2022 R2, SQL Server 2022, ASP.NET Core 10.0, ASP.NET MVC, Silverlight 5, WebMatrix and Visual Studio Lightswitch. Security and performance are at the core of their Magento hosting operations to confirm every website and/or application hosted on their servers is highly secured and performs at optimum level. mutually of the European ASP.NET hosting suppliers, HostForLIFE guarantees 99.9% uptime and fast loading speed. From €3.49/month , HostForLIFE provides you with unlimited disk space, unlimited domains, unlimited bandwidth,etc, for your website hosting needs.
 
https://hostforlifeasp.net/

 

Previous PostOlder Post Home

0 comments:

Post a Comment