Complete Guide to Building a Worker Service in ASP.NET Core

In modern application development, many business processes need to run continuously in the background without direct user interaction. Tasks such as processing messages, consuming APIs, generating reports, sending emails, monitoring queues, and scheduled job execution require a reliable background processing mechanism. This is where the .NET Worker Service becomes an excellent solution.

In this post, we will learn how to create a .NET Worker Service step by step using .NET 10 and C#. We will cover project creation, implementing the BackgroundService class, dependency injection, logging, and running the service across different environments. By the end of this guide, you will have a solid understanding of how to build and deploy production-ready background services in .NET.

Complete Guide to Building a Worker Service in ASP.NET Core

What is a .NET Worker Service?

A .NET Worker Service is a lightweight, long-running service built using ASP.NET Core and the Generic Host framework. It is designed specifically for background workloads and can run as a Windows Service, Linux daemon, or inside Docker containers. With support for dependency injection, logging, configuration management, and asynchronous programming, Worker Services provide a scalable and maintainable approach for handling background tasks in modern .NET applications.

Why Use Worker Services in ASP.NET Core?

Worker Services in ASP.NET Core are designed for running background tasks and long-running processes efficiently without requiring a user interface. They are ideal for applications that need to perform continuous or scheduled operations in the background, such as data processing, queue handling, email notifications, log monitoring, or API integrations.

One of the biggest advantages of using a .NET Worker Service is its lightweight and cross-platform architecture. Since it is built on the ASP.NET Core Generic Host, the same application can run seamlessly on Windows, Linux, Docker containers, or cloud platforms. This makes Worker Services highly suitable for modern microservices and cloud-native applications.

One of the biggest advantages of using a .NET Worker Service is its lightweight and cross-platform architecture. Since it is built on the ASP.NET Core Generic Host, the same application can run seamlessly on Windows, Linux, Docker containers, or cloud platforms. This makes Worker Services highly suitable for modern microservices and cloud-native applications.

Worker Services also provide built-in support for essential enterprise features such as dependency injection, configuration management, structured logging, and asynchronous programming. Developers can easily integrate popular tools like Serilog, RabbitMQ, Kafka, Azure Services, or Quartz.NET for advanced background processing scenarios.

Another important benefit is scalability and maintainability. By separating background operations from the main web application, Worker Services help improve application performance and system reliability. They allow developers to build modular architectures where background jobs can scale independently based on workload requirements.

ASP.NET Core Worker Services are commonly used for:
  • Scheduled jobs and cron-based tasks
  • Queue and message processing
  • Real-time data synchronization
  • File and log processing
  • Email and notification services
  • API polling and integrations
  • Background data cleanup tasks

Overall, Worker Services provide a clean, scalable, and production-ready approach for implementing background processing in modern .NET applications.

Prerequisites for Creating a Worker Service

Before creating a .NET Worker Service, ensure that your development environment is properly configured with the necessary tools and frameworks. Having the correct setup will help you build, run, and debug Worker Services efficiently.

  1. Visual Studio or VS Code
    • Visual Studio 2022 or later
    • Visual Studio Code with C# extensions
    Note: Visual Studio provides built-in templates and debugging support for Worker Services, making development easier for beginners.
  2. The ASP.NET and web development workload (recommended)
  3. .NET SDK
  4. Basic Knowledge of C# and ASP.NET Core

Create a Worker Service Using Visual Studio

Creating a .NET Worker Service using Visual Studio is simple because ASP.NET Core provides a built-in Worker Service template. This template helps developers quickly set up background processing applications with all the required configurations.

Follow the steps below to create your first Worker Service application.
  1. Open Visual Studio
  2. Click on Create a new project
  3. Select Worker Service Template
  4. In the project template search box, type: Worker Service
  5. Select the Worker Service template from the list and click Next.
  6. Configure Project Details
    • Project Name: WorkerServiceDemo
    • Location: Choose your preferred folder
    • Solution Name: WorkerServiceDemo
  7. Click Next to continue.
  8. Choose .NET Version
  9. Click Create.
  10. Run the Worker Service

Explore the Project Structure

Once the project is created, Visual Studio generates the default Worker Service files.
Important files include:
  • Program.cs: This file configures the application host and registers the Worker Service.
  • Worker.cs: This is the main background service class where the long-running task logic is implemented using the BackgroundService class.
  • appsettings.json: Used for storing application configuration settings such as logging, connection strings, or custom settings.

Understand the Default Worker Code

Visual Studio automatically creates sample code inside the Worker.cs file.

public class Worker : BackgroundService
{
  private readonly ILogger<Worker> _logger;
  public Worker(ILogger<Worker> logger)
  {
    _logger = logger;
  }
  protected override async Task ExecuteAsync(CancellationToken stoppingToken)
  {
    while (!stoppingToken.IsCancellationRequested)
    {
      _logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
      await Task.Delay(1000, stoppingToken);
    }
  }
}

This code continuously runs in the background until the application stops. The base class BackgroundService, which implements the IHostedService interface, enables this code to run in the background.

Worker Lifecycle

Startup Flow

	Application Starts
			↓
	Host Builds Services
			↓
      Worker Created
			↓
	ExecuteAsync Starts
			↓
	Loop Runs Repeatedly
    

Shutdown Flow

	Application Stop Requested
       			↓
	Cancellation Token Triggered
       			↓
			Loop Exits
       			↓
    Worker Stops Gracefully
    

Read Configuration from appsettings.json

In a .NET Worker Service, you can read values from appsettings.json (not usually .js) using the built-in configuration system.

Example structure:

 // appsettings.json
{
  "AppSettings": {
    "ApiUrl": "https://example.com",
    "RetryCount": 3
  }
}

In a Worker Service, the generic Host and configuration from appsettings.json is loaded automatically. In this example, we will learn how to read the settings from appsettings.json using strongly typed classes.

Create POCO class

public class MySettings
{
public string ApiUrl { get; set; }
public int RetryCount { get; set; }
}

Register in Program.cs: Update your Program.cs file with the following code.
var builder = Host.CreateDefaultBuilder(args);
builder.ConfigureServices((hostContext, services) =>
{
  services.Configure<AppSettings>(
  hostContext.Configuration.GetSection("AppSettings"));
  services.AddHostedService<Worker>();
  });
  var host = builder.Build();
  host.Run();

Adding Dependency Injection in Worker Service

To add Dependency Injection (DI) in a .NET Worker Service, you use the built-in hosting and service container provided by Microsoft.Extensions.Hosting.

Lets say you have a class MessageService which implements IMessageService and you want to add this class as service. Example service interface and implementation:


public interface IMessageService
{
  void Send(string message);
}
public class MessageService : IMessageService
{
  public void Send(string message)
  {
    Console.WriteLine(message);
  }
}

Register the Service in Program.cs

var builder = Host.CreateDefaultBuilder(args);
builder.ConfigureServices((hostContext, services) =>
{
  services.Configure<AppSettings>(
  hostContext.Configuration.GetSection("AppSettings"));
  //adding DI
  services.AddSingleton<IMessageService, MessageService>();
  services.AddHostedService<Worker>();
  });

Inject the Dependency into Worker
public class Worker : BackgroundService
{
  private readonly IMessageService _messageService;
  public Worker(IMessageService messageService)
  {
    _messageService = messageService;
  }
  protected override async Task ExecuteAsync(CancellationToken stoppingToken)
  {
    while (!stoppingToken.IsCancellationRequested)
    {
      _messageService.Send($"Worker running at: {DateTime.Now}");
      await Task.Delay(1000, stoppingToken);
    }
  }
}

Logging in Worker Services

Logging is an essential feature in a Worker Service because background applications usually run continuously without a user interface. Logs help you:
  • Monitor application activity
  • Track errors and exceptions
  • Debug issues
  • Analyze application behavior
  • Audit background operations

In .NET Worker Services, logging is built into the hosting framework using the ILogger interface. Here will see the code example of Serilog.

To log into/through Worker Services using Serilog in a .NET Worker Service, the standard approach is:
  1. Install Serilog packages
  2. Configure Serilog in Program.cs
  3. Replace default logging with Serilog
  4. Inject and use ILogger<T> in workers

Install required packages

dotnet add package Serilog.AspNetCore
dotnet add package Serilog.Sinks.Console
dotnet add package Serilog.Sinks.File
dotnet add package Serilog.Settings.Configuration

Configure appsettings.json

{
  "Serilog": {
  "Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.File" ],
  "MinimumLevel": {
    "Default": "Information",
    "Override": {
      "Microsoft": "Warning",
      "System": "Warning"
    }
    },
    "WriteTo": [
      {
        "Name": "Console"
        },
        {
          "Name": "File",
          "Args": {
            "path": "logs/log-.txt",
            "rollingInterval": "Day",
            "retainedFileCountLimit": 7
          }
        }
      ],
    "Enrich": [ "FromLogContext", "WithMachineName", "WithThreadId" ],
    "Properties": {
      "Application": "WorkerService"
    }
  }
}

Configure Serilog in Program.cs

using Serilog;
var builder = Host.CreateDefaultBuilder(args);
builder.UseWindowsService();
builder.ConfigureServices((hostContext, services) =>
{
  services.Configure<AppSettings>(
  hostContext.Configuration.GetSection("AppSettings"));
  //Ading DI
  services.AddSingleton<IMessageService, MessageService>();
  services.AddHostedService<Worker>();
});
builder.UseSerilog((context, services, configuration) =>
{
  configuration
  .ReadFrom.Configuration(context.Configuration)
  .ReadFrom.Services(services)
  .Enrich.FromLogContext();
});
var host = builder.Build();
host.Run();

Use logging inside Worker

See the above Worker.cs which describes how to use the loggin inside the worker service

Understanding BackgroundService and IHostedService

In ASP.NET Core Worker Services, IHostedService and BackgroundService are the core components used for implementing background tasks and long-running processes. Understanding how these two work is essential for building scalable and reliable Worker Service applications.

What is IHostedService?

IHostedService is an interface provided by ASP.NET Core that defines methods for starting and stopping background services. It allows tasks to run alongside the main application lifecycle.

The interface contains two important methods:

public interface IHostedService
{
  Task StartAsync(CancellationToken cancellationToken);
  Task StopAsync(CancellationToken cancellationToken);
}

StartAsync()

This method is executed when the application starts. It is commonly used to initialize resources, establish connections, or start background operations.

StopAsync()

This method is called when the application is shutting down. It helps gracefully stop background tasks and release resources properly.

IHostedService Example


public class SampleHostedService : IHostedService
{
  public Task StartAsync(CancellationToken cancellationToken)
  {
    Console.WriteLine("Service Started");
    return Task.CompletedTask;
  }
  public Task StopAsync(CancellationToken cancellationToken)
  {
    Console.WriteLine("Service Stopped");
    return Task.CompletedTask;
  }
}

What is BackgroundService?

BackgroundService is an abstract base class that implements IHostedService. It simplifies background task development by providing a built-in structure for long-running operations.

Instead of manually implementing StartAsync() and StopAsync(), developers only need to override the ExecuteAsync() method.

ExecuteAsync()

ExecuteAsync() is the most important method in a .NET Worker Service when using the BackgroundService class. It contains the core logic that runs in the background for the entire lifetime of the service.

When a Worker Service starts, ASP.NET Core automatically calls the ExecuteAsync() method. This method continues running until the application is stopped or a cancellation request is triggered.

BackgroundService Example


public class Worker : BackgroundService
{
  private readonly ILogger<Worker> _logger;
  public Worker(ILogger<Worker> logger)
  {
    _logger = logger;
  }
  protected override async Task ExecuteAsync(CancellationToken stoppingToken)
  {
    while (!stoppingToken.IsCancellationRequested)
    {
      _logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
      await Task.Delay(1000, stoppingToken);
    }
  }
}

Difference Between IHostedService and BackgroundService

FeatureIHostedServiceBackgroundService
TypeInterfaceAbstract Class
ComplexityMore manual implementationSimpler implementation
Lifecycle HandlingManualBuilt-in
Best ForCustom startup/shutdown logicContinuous background tasks
ExecuteAsync SupportNoYes

When to UseIHostedService

Use IHostedService when:
  • You need complete control over service lifecycle
  • Startup and shutdown operations are more important
  • The task is not continuously running

When to Use BackgroundService

Use BackgroundService when:
  • Running long-running background tasks
  • Creating polling services
  • Processing queues or messages
  • Implementing scheduled operations
  • Building microservice workers

Overall, BackgroundService is the preferred choice for most modern .NET Worker Service applications because it reduces complexity while providing robust background task execution support./p>

Summary

Thanks

Kailash Chandra Behera

I am an IT professional with over 13 years of experience in the full software development life cycle for Windows, services, and web-based applications using Microsoft .NET technologies.

Previous Post Next Post

نموذج الاتصال