Running Background Jobs in ASP.NET Core Using IHostedService – No Extra Services Required


🧵 Can your ASP.NET Core app send emails, clean up logs, or sync data in the background?
Yes – without using Hangfire, Quartz, or external schedulers!

It's the hidden gem that lets you run background jobs inside your web app – perfect for lightweight tasks.

🧩 Introduction to IHostedService and BackgroundService

🔹 What is IHostedService?

In .NET, IHostedService is an interface that allows you to run background tasks as part of your application’s lifetime. It’s part of the Microsoft.Extensions.Hosting namespace and gets registered with the Generic Host used in ASP.NET Core applications.

  • When the app starts, the host calls: StartAsync(CancellationToken)

  • And when the app shuts down, it calls: StopAsync(CancellationToken)

This is perfect for scenarios where you need to start a job when the app starts and clean up resources before shutdown.


🔹 What is BackgroundService?

BackgroundService is an abstract base class that simplifies the use of IHostedService. Instead of manually implementing StartAsync and StopAsync, you only need to override the ExecuteAsync(CancellationToken stoppingToken) method.

This makes it easier and cleaner to implement loop-based background jobs, such as:

  • Periodic polling (e.g., checking a database or queue).

  • Repeating tasks with delays.

  • Background processing of internal messages.


✅ Why Use IHostedService in ASP.NET Core?

  • Run background jobs inside an API/web app.

  • Ideal for lightweight or scheduled tasks.

  • No need to host a separate process or install a Windows service.


🛠️ Step-by-Step Guide: Running a Background Job in ASP.NET Core

Step 1: Create ASP.NET Core Web API

dotnet new webapi -n HostedServiceDemo
cd HostedServiceDemo

Step 2: Create the Background Job Class

public class EmailReminderService : BackgroundService
{
    private readonly ILogger<EmailReminderService> _logger;
    private readonly IServiceScopeFactory _scopeFactory;

    public EmailReminderService(ILogger<EmailReminderService> logger, IServiceScopeFactory scopeFactory)
    {
        _logger = logger;
        _scopeFactory = scopeFactory;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        _logger.LogInformation("Email Reminder Service started.");
        while (!stoppingToken.IsCancellationRequested)
        {
            using var scope = _scopeFactory.CreateScope();
            var emailService = scope.ServiceProvider.GetRequiredService<IEmailSender>();

            await emailService.SendPendingRemindersAsync();
            await Task.Delay(TimeSpan.FromMinutes(5), stoppingToken);
        }
    }
}

Step 3: Register the Service

In Program.cs:

builder.Services.AddHostedService<EmailReminderService>();
builder.Services.AddScoped<IEmailSender, EmailSender>(); // your own service

💡 Bonus Tips

  • Use IServiceScopeFactory for scoped dependencies.

  • Handle cancellation tokens gracefully.

  • Log start, stop, and error events.

  • Don’t block the main thread (avoid Task.Wait() or .Result).


🧪 Common Use Cases

  • Sending emails.

  • Cleaning up temp files.

  • Refreshing cache.

  • Processing internal queues.

  • Retrying failed webhooks.


📦 When NOT to Use It

  • For CPU-heavy or long-running parallel jobs → prefer Worker Service.

  • When job failure needs retry logic or persistence → consider Hangfire or Azure Functions.


🔄 IHostedService vs Worker Service: What's the Difference?

FeatureIHostedService in ASP.NET CoreWorker Service (Standalone)
PurposeRun background jobs inside a web appDedicated background processing app
🧩 Host TypeASP.NET Core Web Host (with web APIs).NET Generic Host (console app)
🔗 Tied to Web AppYes (lives alongside your controllers)No (runs independently of web apps)
🧪 Best ForLightweight, app-scoped jobsLong-running jobs, queue consumers, daemons
🔄 LifecycleStarts/stops with the web appRuns continuously as a service or container
🔧 DeploymentDeployed with the API/web appCan run as Windows Service, Linux daemon, Docker
💬 Typical Use CasesEmail reminders, log cleanup, cache refreshRabbitMQ consumers, scheduled tasks, file watchers
🔍 ScalabilityLimited to app's lifecycleCan scale independently

🎉 Conclusion

With IHostedService and BackgroundService, you can run background jobs inside your ASP.NET Core app without deploying a separate service or adding external dependencies. It’s ideal for background logic that’s closely tied to your web app simple, native, and production-ready.

👉 Already using Worker Services for heavy lifting? This approach complements them perfectly for lightweight internal tasks.

  • No extra tools needed

  • Integrates tightly with your existing ASP.NET Core app

  • Simple and powerful for many real-world scenarios

0
Subscribe to my newsletter

Read articles from Pranali Kulkarni directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Pranali Kulkarni
Pranali Kulkarni