Worker Service Projects
Create a standalone Worker Service, configure DI and logging, and deploy it as a Windows Service or Linux daemon.
Worker Service Projects is a free C# Academy lesson on CoddyKit — lesson 2 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the C# Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
What Is a Worker Service?
A Worker Service is a .NET project template for building long-running background applications — no web server, no HTTP endpoints. It's a lightweight host perfect for queue processors, scheduled tasks, and daemon-style services.
Creating a Worker Service
Use the CLI template to scaffold a Worker Service project. It generates a minimal Program.cs and a Worker.cs class that inherits from BackgroundService.
# Create a new Worker Service project
dotnet new worker -n OrderProcessor
# Generated structure:
# OrderProcessor/
# Program.cs — host configuration
# Worker.cs — your BackgroundService subclass
# appsettings.jsonWorker Service Program.cs
The generated Program.cs uses the Generic Host. You configure DI, logging, configuration, and register your worker — identical to ASP.NET Core but without the web server.
using Microsoft.Extensions.Hosting;
var builder = Host.CreateApplicationBuilder(args);
// Register services
builder.Services.AddDbContext<AppDbContext>(opt =>
opt.UseSqlServer(builder.Configuration.GetConnectionString("Default")));
builder.Services.AddScoped<IOrderRepository, OrderRepository>();
builder.Services.AddHostedService<OrderProcessorWorker>();
var host = builder.Build();
host.Run();The Worker Class
Inherit from BackgroundService and implement ExecuteAsync. The host calls it on startup and passes a cancellation token that fires on shutdown.
public class OrderProcessorWorker : BackgroundService
{
private readonly IServiceScopeFactory _factory;
private readonly ILogger<OrderProcessorWorker> _logger;
public OrderProcessorWorker(
IServiceScopeFactory factory,
ILogger<OrderProcessorWorker> logger)
{
_factory = factory;
_logger = logger;
}
protected override async Task ExecuteAsync(CancellationToken ct)
{
while (!ct.IsCancellationRequested)
{
using var scope = _factory.CreateScope();
var repo = scope.ServiceProvider.GetRequiredService<IOrderRepository>();
var pending = await repo.GetPendingAsync(ct);
foreach (var order in pending)
await ProcessOrderAsync(order, ct);
await Task.Delay(TimeSpan.FromSeconds(10), ct);
}
}
private Task ProcessOrderAsync(Order o, CancellationToken ct) =>
Task.Delay(100, ct); // placeholder
}Configuration & DI in Workers
Worker Services support the full .NET configuration system — appsettings, environment variables, user secrets. Inject IConfiguration or strongly typed options.
builder.Services.Configure<WorkerSettings>(
builder.Configuration.GetSection("Worker"));
public class OrderProcessorWorker : BackgroundService
{
private readonly WorkerSettings _settings;
public OrderProcessorWorker(IOptions<WorkerSettings> opts, ...)
=> _settings = opts.Value;
protected override async Task ExecuteAsync(CancellationToken ct)
{
while (!ct.IsCancellationRequested)
{
// ...
await Task.Delay(_settings.PollIntervalSeconds * 1000, ct);
}
}
}Logging in Worker Services
The Generic Host configures logging automatically. Use ILogger<T> for structured logging. In production, configure Serilog, Application Insights, or another provider.
// Add Serilog to a Worker Service
builder.Host.UseSerilog((ctx, logConfig) =>
logConfig
.ReadFrom.Configuration(ctx.Configuration)
.WriteTo.Console()
.WriteTo.Seq(ctx.Configuration["Seq:ServerUrl"]!));
// Structured logging in the worker:
_logger.LogInformation("Processing {Count} orders at {Time}",
orders.Count, DateTimeOffset.UtcNow);
_logger.LogError(ex, "Failed to process order {OrderId}", order.Id);Running as a Windows Service
Use UseWindowsService() to run your Worker as a Windows Service. The service starts/stops with the OS and survives user logouts.
// dotnet add package Microsoft.Extensions.Hosting.WindowsServices
builder.Services.AddWindowsService(options =>
options.ServiceName = "OrderProcessor");
// Build and publish:
// dotnet publish -c Release -o ./publish
// Install as Windows Service:
// sc create OrderProcessor binpath="C:\services\publish\OrderProcessor.exe"
// sc start OrderProcessorRunning as a Linux Systemd Daemon
Use UseSystemd() to integrate with systemd on Linux. The service receives proper stop signals and integrates with journald logging.
// dotnet add package Microsoft.Extensions.Hosting.Systemd
builder.Services.AddSystemd();
// Systemd unit file: /etc/systemd/system/orderprocessor.service
// [Unit]
// Description=Order Processor Worker
// [Service]
// Type=notify
// ExecStart=/usr/bin/dotnet /app/OrderProcessor.dll
// Restart=always
// [Install]
// WantedBy=multi-user.target
// Commands:
// sudo systemctl enable orderprocessor
// sudo systemctl start orderprocessor
// sudo journalctl -u orderprocessor -fRunning in Docker
Worker Services are ideal for Docker containers — no port mapping needed, just run the process in a loop until the container stops.
# Dockerfile
FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build
WORKDIR /src
COPY . .
RUN dotnet publish -c Release -o /app
FROM mcr.microsoft.com/dotnet/runtime:9.0
WORKDIR /app
COPY --from=build /app .
ENTRYPOINT ["dotnet", "OrderProcessor.dll"]
# docker-compose.yml:
# services:
# worker:
# build: .
# environment:
# - ConnectionStrings__Default=Server=db;...
# depends_on: [db]Real-World: Email Digest Worker
A complete worker that sends daily email digests by reading from a database and dispatching via an email service.
public class EmailDigestWorker : BackgroundService
{
private readonly IServiceScopeFactory _factory;
private readonly ILogger<EmailDigestWorker> _log;
protected override async Task ExecuteAsync(CancellationToken ct)
{
// Run daily at midnight UTC
while (!ct.IsCancellationRequested)
{
var now = DateTime.UtcNow;
var next = now.Date.AddDays(1); // next midnight
await Task.Delay(next - now, ct);
using var scope = _factory.CreateScope();
var mailer = scope.ServiceProvider.GetRequiredService<IDigestMailer>();
try { await mailer.SendDailyDigestsAsync(ct); }
catch (Exception ex) { _log.LogError(ex, "Digest failed"); }
}
}
}Quick Check
What is the main difference between a Worker Service project and an ASP.NET Core Web API project?
Recap: Worker Service Projects
Key takeaways:
- Worker Service = Generic Host + BackgroundService, no web server
- Full DI, logging, and configuration support — just no HTTP
UseWindowsService()for Windows Service deploymentUseSystemd()for Linux daemon with journald integration- Deploy in Docker containers for cloud-native background processing
- Always use IServiceScopeFactory for scoped dependencies in the worker
Frequently asked questions
Is the “Worker Service Projects” lesson free?
Yes — the full text of “Worker Service Projects” is free to read here on the web, and the C# Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the C# Academy course, upgrade to CoddyKit PRO.
What will I learn in “Worker Service Projects”?
Create a standalone Worker Service, configure DI and logging, and deploy it as a Windows Service or Linux daemon. You practise C# Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start C# Academy?
No prior experience is required. C# Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 2 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “Worker Service Projects” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this C# Academy lesson?
Yes. Every C# Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- IHostedService & BackgroundService
- Worker Service Projects
- Periodic Tasks & Timers
- Quartz.NET Scheduled Jobs