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?
Feature | IHostedService in ASP.NET Core | Worker Service (Standalone) |
✅ Purpose | Run background jobs inside a web app | Dedicated background processing app |
🧩 Host Type | ASP.NET Core Web Host (with web APIs) | .NET Generic Host (console app) |
🔗 Tied to Web App | Yes (lives alongside your controllers) | No (runs independently of web apps) |
🧪 Best For | Lightweight, app-scoped jobs | Long-running jobs, queue consumers, daemons |
🔄 Lifecycle | Starts/stops with the web app | Runs continuously as a service or container |
🔧 Deployment | Deployed with the API/web app | Can run as Windows Service, Linux daemon, Docker |
💬 Typical Use Cases | Email reminders, log cleanup, cache refresh | RabbitMQ consumers, scheduled tasks, file watchers |
🔍 Scalability | Limited to app's lifecycle | Can 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
Subscribe to my newsletter
Read articles from Pranali Kulkarni directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
