A Windows Service is a long-running application that runs in the background without requiring a user to keep a console window open. In modern .NET, the recommended approach is to build a Worker Service using BackgroundService and configure it to run under the Windows Service infrastructure. Microsoft documents this approach for .NET 8 and later. (Microsoft Learn)
Below is a blog-ready article with a real-time example, architecture, code, deployment, logging, configuration, error handling, recovery, and troubleshooting.
Windows Services in .NET: Complete Guide with Real-Time Example
Introduction
In enterprise applications, we often have requirements where some processing must happen continuously in the background without a user manually starting the application.
For example:
Process pending orders
Generate invoices
Send notification emails
Read files from a folder
Synchronize data between systems
Process messages from a queue
Generate reports
Monitor application health
Clean up temporary files
Synchronize data with a third-party API
A normal console application is not ideal for these scenarios because someone has to manually start it.
A Windows Service solves this problem.
A Windows Service can start automatically when Windows starts and continue running in the background.
Modern .NET provides the Worker Service template and BackgroundService for implementing these applications.
1. What is a Windows Service?
A Windows Service is an application designed to run in the background under the control of the Windows Service Control Manager (SCM).
Unlike a normal desktop application:
Normal Console Application
User
|
v
Start Application
|
v
Console Window
|
v
Application RunningA Windows Service works more like:
Windows Operating System
|
v
Service Control Manager
|
v
Order Processing Service
|
v
Background Worker
|
+----> Database
|
+----> APIs
|
+----> File System
|
+----> Message QueueThe Service Control Manager can start, stop and monitor the service.
2. Why Do We Need Windows Services?
Imagine an e-commerce application.
Customers place orders throughout the day.
The application stores orders in SQL Server.
Instead of processing everything inside the Web API request, we can have a background service that periodically checks for pending orders.
Customer
|
v
Angular Application
|
v
.NET Web API
|
v
SQL Server
|
| Pending Orders
v
Windows Service
|
+---- Process Order
|
+---- Generate Invoice
|
+---- Update Status
|
+---- Send NotificationThis is a common enterprise architecture.
3. Real-Time Example
Let's build a real-world application called:
Order Processing Windows Service
Our requirement is:
Every 30 seconds, the Windows Service should check SQL Server for pending orders and process them.
The workflow will be:
SQL Server
|
| Pending Orders
v
Windows Service
|
v
Read Order
|
v
Process Order
|
v
Generate Invoice
|
v
Update Order Status
|
v
Log Result4. Worker Service vs Windows Service
These two terms are often confused.
Worker Service
A Worker Service is a .NET application designed for long-running background processing.
Windows Service
A Windows Service is the way the operating system hosts and manages a background application.
Therefore:
Worker Service
+
UseWindowsService()
|
v
Windows ServiceThe modern .NET approach is to create a Worker Service and configure it to run as a Windows Service.
Microsoft recommends using the Worker Service template with BackgroundService for this scenario. (Microsoft Learn)
5. Prerequisites
You need:
Windows OS
.NET SDK
Visual Studio or VS Code
SQL Server if using the database example
Administrator privileges for installing the Windows Service
Microsoft's current Windows Service documentation uses .NET 8 or later as the prerequisite baseline. (Microsoft Learn)
6. Create the Worker Service
Using the .NET CLI:
dotnet new worker -n OrderProcessingServiceMove into the project:
cd OrderProcessingServiceRun the application:
dotnet runThe Worker Service template creates a background worker application.
The template can also be created from Visual Studio by selecting:
Create a new project
|
v
Worker Service7. Project Structure
Our project can look like this:
OrderProcessingService
│
├── Program.cs
├── Worker.cs
├── appsettings.json
│
├── Models
│ └── Order.cs
│
├── Services
│ ├── IOrderProcessor.cs
│ └── OrderProcessor.cs
│
└── Data
└── OrderRepository.csA good architecture separates:
Worker
|
v
Business Service
|
v
Repository
|
v
DatabaseThe Worker should not contain all business logic.
8. Install Windows Service Package
Install:
dotnet add package Microsoft.Extensions.Hosting.WindowsServicesThis package provides Windows Service integration for the .NET hosting infrastructure. (NuGet)
9. Understanding BackgroundService
The main class of our Worker Service will inherit from:
BackgroundServiceExample:
public class Worker : BackgroundService
{
protected override async Task ExecuteAsync(
CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
// Background processing
await Task.Delay(
TimeSpan.FromSeconds(30),
stoppingToken);
}
}
}The important method is:
ExecuteAsync()This is where the background processing happens.
10. Understanding CancellationToken
A Windows Service must be able to stop gracefully.
Suppose Windows sends a stop command.
We don't want the application to suddenly terminate in the middle of an operation.
Therefore:
CancellationToken stoppingTokenis provided.
We can check:
while (!stoppingToken.IsCancellationRequested)This means:
Continue processing until Windows tells the service to stop.
11. Program.cs
Now configure our application.
using Microsoft.Extensions.Hosting;
var builder = Host.CreateApplicationBuilder(args);
builder.Services.AddWindowsService(options =>
{
options.ServiceName = "Order Processing Service";
});
builder.Services.AddHostedService<Worker>();
var host = builder.Build();
host.Run();The important line is:
builder.Services.AddWindowsService();This configures the application to work with Windows Service lifetime management. Microsoft's current documentation uses this approach with Host.CreateApplicationBuilder. (Microsoft Learn)
12. Worker.cs
Create our worker:
public class Worker : BackgroundService
{
private readonly ILogger<Worker> _logger;
public Worker(ILogger<Worker> logger)
{
_logger = logger;
}
protected override async Task ExecuteAsync(
CancellationToken stoppingToken)
{
_logger.LogInformation(
"Order Processing Service started.");
while (!stoppingToken.IsCancellationRequested)
{
try
{
_logger.LogInformation(
"Checking for pending orders.");
await ProcessOrders(stoppingToken);
}
catch (Exception ex)
{
_logger.LogError(
ex,
"Error while processing orders.");
}
await Task.Delay(
TimeSpan.FromSeconds(30),
stoppingToken);
}
_logger.LogInformation(
"Order Processing Service stopped.");
}
private async Task ProcessOrders(
CancellationToken cancellationToken)
{
// Order processing logic
await Task.CompletedTask;
}
}13. Why Use Task.Delay?
Suppose we want to execute our process every 30 seconds.
We can use:
await Task.Delay(
TimeSpan.FromSeconds(30),
stoppingToken);The flow becomes:
Service Starts
|
v
Process Orders
|
v
Wait 30 Seconds
|
v
Process Orders
|
v
Wait 30 Seconds
|
v
Continue...14. Don't Use Thread.Sleep
Avoid:
Thread.Sleep(30000);Prefer:
await Task.Delay(
TimeSpan.FromSeconds(30),
stoppingToken);Why?
Thread.Sleep() blocks the thread.
Task.Delay() allows asynchronous waiting and can respond to cancellation.
15. Create Order Model
Create:
Models/Order.csnamespace OrderProcessingService.Models;
public class Order
{
public int Id { get; set; }
public string OrderNumber { get; set; } = string.Empty;
public decimal Amount { get; set; }
public string Status { get; set; } = string.Empty;
public DateTime CreatedDate { get; set; }
}16. Database Table
Suppose we have this SQL Server table:
CREATE TABLE Orders
(
Id INT IDENTITY PRIMARY KEY,
OrderNumber VARCHAR(50) NOT NULL,
Amount DECIMAL(18,2) NOT NULL,
Status VARCHAR(20) NOT NULL,
CreatedDate DATETIME2 NOT NULL
);Insert sample records:
INSERT INTO Orders
(
OrderNumber,
Amount,
Status,
CreatedDate
)
VALUES
(
'ORD1001',
2500,
'Pending',
GETDATE()
);
INSERT INTO Orders
(
OrderNumber,
Amount,
Status,
CreatedDate
)
VALUES
(
'ORD1002',
3500,
'Pending',
GETDATE()
);17. Create Repository
Create:
Data/OrderRepository.csFor demonstration, we can use ADO.NET.
using Microsoft.Data.SqlClient;
using OrderProcessingService.Models;
public class OrderRepository
{
private readonly string _connectionString;
public OrderRepository(string connectionString)
{
_connectionString = connectionString;
}
public async Task<List<Order>> GetPendingOrdersAsync(
CancellationToken cancellationToken)
{
var orders = new List<Order>();
using var connection =
new SqlConnection(_connectionString);
await connection.OpenAsync(cancellationToken);
var command = new SqlCommand(
"""
SELECT TOP 10
Id,
OrderNumber,
Amount,
Status,
CreatedDate
FROM Orders
WHERE Status = 'Pending'
ORDER BY Id
""",
connection);
using var reader =
await command.ExecuteReaderAsync(
cancellationToken);
while (await reader.ReadAsync(cancellationToken))
{
orders.Add(new Order
{
Id = reader.GetInt32(0),
OrderNumber = reader.GetString(1),
Amount = reader.GetDecimal(2),
Status = reader.GetString(3),
CreatedDate = reader.GetDateTime(4)
});
}
return orders;
}
}18. Register Repository Using Dependency Injection
Instead of creating the repository manually inside the Worker, use Dependency Injection.
Example:
builder.Services.AddSingleton<OrderRepository>();However, for production applications, it is usually better to register database-related services according to their actual lifetime and dependency behavior.
For example:
builder.Services.AddScoped<IOrderProcessor, OrderProcessor>();For scoped services inside a BackgroundService, create an explicit scope using IServiceScopeFactory.
19. Business Service
Create:
Services/IOrderProcessor.cspublic interface IOrderProcessor
{
Task ProcessAsync(
CancellationToken cancellationToken);
}Implementation:
public class OrderProcessor : IOrderProcessor
{
private readonly OrderRepository _repository;
private readonly ILogger<OrderProcessor> _logger;
public OrderProcessor(
OrderRepository repository,
ILogger<OrderProcessor> logger)
{
_repository = repository;
_logger = logger;
}
public async Task ProcessAsync(
CancellationToken cancellationToken)
{
var orders =
await _repository.GetPendingOrdersAsync(
cancellationToken);
foreach (var order in orders)
{
_logger.LogInformation(
"Processing order {OrderNumber}",
order.OrderNumber);
// Business logic
_logger.LogInformation(
"Order {OrderNumber} processed successfully.",
order.OrderNumber);
}
}
}20. Worker with Dependency Injection
Now our Worker becomes cleaner.
public class Worker : BackgroundService
{
private readonly IServiceScopeFactory _scopeFactory;
private readonly ILogger<Worker> _logger;
public Worker(
IServiceScopeFactory scopeFactory,
ILogger<Worker> logger)
{
_scopeFactory = scopeFactory;
_logger = logger;
}
protected override async Task ExecuteAsync(
CancellationToken stoppingToken)
{
_logger.LogInformation(
"Order Processing Service started.");
while (!stoppingToken.IsCancellationRequested)
{
try
{
using var scope =
_scopeFactory.CreateScope();
var processor =
scope.ServiceProvider
.GetRequiredService<IOrderProcessor>();
await processor.ProcessAsync(
stoppingToken);
}
catch (OperationCanceledException)
when (stoppingToken.IsCancellationRequested)
{
break;
}
catch (Exception ex)
{
_logger.LogError(
ex,
"Unexpected error.");
}
await Task.Delay(
TimeSpan.FromSeconds(30),
stoppingToken);
}
_logger.LogInformation(
"Order Processing Service stopped.");
}
}This gives us a clean architecture:
Worker
|
v
IOrderProcessor
|
v
OrderProcessor
|
v
OrderRepository
|
v
SQL Server21. appsettings.json
Configuration should not be hard-coded.
Create:
{
"ConnectionStrings": {
"DefaultConnection": "Server=localhost;Database=OrderDb;Trusted_Connection=True;TrustServerCertificate=True"
},
"WorkerSettings": {
"IntervalSeconds": 30,
"BatchSize": 10
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.Hosting.Lifetime": "Information"
}
}
}22. Using Configuration
Create:
public class WorkerSettings
{
public int IntervalSeconds { get; set; }
public int BatchSize { get; set; }
}Register it:
builder.Services.Configure<WorkerSettings>(
builder.Configuration.GetSection("WorkerSettings"));Now the interval can be changed without modifying the code.
23. Complete Program.cs
Our final Program.cs can look like:
using Microsoft.Extensions.Hosting;
var builder = Host.CreateApplicationBuilder(args);
builder.Services.AddWindowsService(options =>
{
options.ServiceName = "Order Processing Service";
});
builder.Services.Configure<WorkerSettings>(
builder.Configuration.GetSection("WorkerSettings"));
var connectionString =
builder.Configuration.GetConnectionString(
"DefaultConnection");
builder.Services.AddSingleton(
new OrderRepository(connectionString!));
builder.Services.AddScoped<IOrderProcessor, OrderProcessor>();
builder.Services.AddHostedService<Worker>();
var host = builder.Build();
host.Run();24. Logging
Logging is extremely important for Windows Services because there is no console window when the service is running in production.
We can use:
_logger.LogInformation(
"Order {OrderNumber} processed.",
order.OrderNumber);Other levels include:
_logger.LogDebug("Debug information");
_logger.LogInformation("Information");
_logger.LogWarning("Warning");
_logger.LogError("Error");
_logger.LogCritical("Critical failure");25. Windows Event Viewer
When running as a Windows Service, logs can be written to the Windows Event Log.
Microsoft's Windows Service hosting integration supports Event Log logging, and UseWindowsService/AddWindowsService configures Windows Service behavior and Event Log integration. (Microsoft Learn)
You can open:
Start
|
v
Event Viewer
|
v
Windows Logs
|
v
ApplicationThen search for events generated by your application.
26. Important Difference: Console vs Windows Service
During development:
dotnet runThe application runs as a console process.
After installation:
Windows
|
v
Service Control Manager
|
v
Order Processing Service
|
v
WorkerThe same application can therefore be useful both locally and as a Windows Service.
27. Publish the Application
Before installing the service, publish the application.
For a Windows x64 deployment:
dotnet publish -c Release -r win-x64 --self-contained trueYou can also publish as a single executable.
Microsoft recommends publishing a Worker Service as a single-file executable for Windows Service deployment because it reduces deployment-file complexity. (Microsoft Learn)
Example:
dotnet publish -c Release -r win-x64 --self-contained true /p:PublishSingleFile=trueThe published application will be under a path similar to:
bin\Release\net9.0\win-x64\publish\The exact target framework depends on the .NET version used by your project.
28. Installing the Windows Service
Open:
PowerShellor:
Command Promptas Administrator.
Navigate to the published executable.
Then:
sc.exe create "Order Processing Service" binPath= "C:\Services\OrderProcessingService\OrderProcessingService.exe"If successful, Windows reports:
[SC] CreateService SUCCESSMicrosoft documents sc.exe create as the native Service Control Manager approach for creating the service. (Microsoft Learn)
29. Start the Service
Run:
sc.exe start "Order Processing Service"Or open:
ServicesFind:
Order Processing ServiceThen:
Right Click
|
v
Start30. Service Lifecycle
The complete lifecycle looks like:
Windows Boot
|
v
Service Control Manager
|
v
Start Service
|
v
.NET Host
|
v
BackgroundService
|
v
ExecuteAsync()
|
v
Process Orders
|
v
Wait
|
+--------+
|
v
Process AgainWhen Windows stops the service:
Windows
|
v
Stop Request
|
v
CancellationToken
|
v
ExecuteAsync exits
|
v
Host shuts down
|
v
Service stopped31. Stop the Service
sc.exe stop "Order Processing Service"Or use:
Services
|
v
Order Processing Service
|
v
Stop32. Delete the Service
If you want to completely remove it:
sc.exe stop "Order Processing Service"
sc.exe delete "Order Processing Service"Microsoft notes that a service should be stopped before deleting it. (Microsoft Learn)
33. Configure Automatic Startup
A production service normally should start automatically.
Use:
sc.exe config "Order Processing Service" start= autoNow Windows can start the service automatically during system startup.
34. Configure Service Recovery
One of the biggest advantages of Windows Services is recovery configuration.
Imagine:
Order Processing Service
|
v
Unexpected Error
|
v
Process TerminatesWe want:
Service Failure
|
v
Windows Service Manager
|
v
Restart ServiceMicrosoft provides sc.exe failure for configuring service recovery actions. (Microsoft Learn)
Example:
sc.exe failure "Order Processing Service" reset= 86400 actions= restart/60000/restart/60000/run/1000This can configure restart actions after failures.
35. Why Recovery Is Important
Consider a production server:
2:00 AM
|
v
Service crashes
|
v
Windows detects failure
|
v
Service automatically restarts
|
v
Processing continuesWithout recovery:
Service crashes
|
v
Processing stops
|
v
Manual intervention requiredWith recovery:
Service crashes
|
v
Automatic restart
|
v
Processing continues36. Handling Exceptions
Never allow an unexpected exception to bring down the entire worker loop unnecessarily.
Bad:
while (true)
{
await ProcessOrders();
}Better:
while (!stoppingToken.IsCancellationRequested)
{
try
{
await ProcessOrders(stoppingToken);
}
catch (Exception ex)
{
_logger.LogError(
ex,
"Error processing orders.");
}
await Task.Delay(
TimeSpan.FromSeconds(30),
stoppingToken);
}However, exception handling should be designed carefully. Some failures indicate that the application should stop rather than endlessly retry.
37. Graceful Shutdown
Suppose an order is currently being processed:
Processing Order 1001
|
|
Windows Stop Request
|
v
CancellationTokenThe service should stop accepting new work and allow the current operation to finish when appropriate.
Use:
CancellationTokenthroughout the call chain:
Worker
|
v
Processor
|
v
Repository
|
v
DatabaseFor example:
await connection.OpenAsync(
cancellationToken);and:
await command.ExecuteReaderAsync(
cancellationToken);38. Avoid Long Blocking Operations
Avoid:
Thread.Sleep(...)Avoid synchronous network calls when asynchronous APIs are available.
Prefer:
await httpClient.GetAsync(
url,
cancellationToken);Prefer asynchronous database operations:
await command.ExecuteNonQueryAsync(
cancellationToken);This makes the service more responsive and easier to shut down gracefully.
39. Calling a Third-Party API
Suppose after processing an order we need to notify an external payment service.
Use HttpClient through Dependency Injection.
builder.Services.AddHttpClient(
"PaymentApi",
client =>
{
client.BaseAddress =
new Uri("https://api.example.com/");
});Then:
public class PaymentService
{
private readonly IHttpClientFactory _httpClientFactory;
public PaymentService(
IHttpClientFactory httpClientFactory)
{
_httpClientFactory = httpClientFactory;
}
public async Task NotifyPaymentAsync(
int orderId,
CancellationToken cancellationToken)
{
var client =
_httpClientFactory.CreateClient("PaymentApi");
await client.PostAsJsonAsync(
"payments/process",
new
{
OrderId = orderId
},
cancellationToken);
}
}40. Real Production Architecture
A production implementation could look like:
┌─────────────────────┐
│ SQL Server │
│ │
│ Pending Orders │
└──────────┬──────────┘
│
▼
┌─────────────────────┐
│ Windows Service │
│ │
│ BackgroundService │
└──────────┬──────────┘
│
▼
┌─────────────────────┐
│ Order Processor │
│ │
│ Business Logic │
└──────────┬──────────┘
│
┌──────────────┼──────────────┐
▼ ▼ ▼
SQL Server Payment API Notification API
│ │ │
└──────────────┼──────────────┘
▼
Logging
│
▼
Event Viewer41. Windows Service vs Web API
These applications solve different problems.
| Feature | Web API | Windows Service |
|---|---|---|
| User request | Yes | No |
| HTTP endpoint | Yes | Not required |
| Long-running background work | Not ideal | Excellent |
| Runs continuously | Usually hosted continuously | Yes |
| Trigger | HTTP request | Timer/event/message |
| UI required | No | No |
| Windows Service support | Possible | Native scenario |
| Background processing | Limited/specialized | Excellent |
A Web API is usually request-driven.
A Windows Service is usually background-driven.
42. Windows Service vs BackgroundService
They are not exactly the same thing.
BackgroundService
|
+---- Console Application
|
+---- Windows Service
|
+---- Container
|
+---- Other HostBackgroundService is an abstraction for implementing long-running hosted background work.
Windows Service hosting is one way to host that worker.
43. Timer-Based Processing
For periodic work, another pattern is using PeriodicTimer.
Example:
protected override async Task ExecuteAsync(
CancellationToken stoppingToken)
{
using var timer =
new PeriodicTimer(
TimeSpan.FromSeconds(30));
while (await timer.WaitForNextTickAsync(
stoppingToken))
{
await ProcessOrders(
stoppingToken);
}
}This can make periodic processing easier to read.
44. Important Production Consideration: Duplicate Processing
Suppose:
Worker
|
v
Gets Order 1001
|
v
Starts ProcessingBefore updating the status, the service crashes.
After restart:
Worker
|
v
Gets Order 1001 againNow the same order could be processed twice.
This is a major production concern.
We need an idempotent processing strategy.
45. Use Status Transitions
Instead of:
Pending
|
v
Processeduse:
Pending
|
v
Processing
|
v
CompletedIf something fails:
Processing
|
v
FailedExample:
Pending
|
v
Processing
|
+------> Failed
|
v
CompletedThis allows us to understand exactly where the order is.
46. Database Transaction
Critical operations can use transactions.
Conceptually:
BEGIN TRANSACTION
Get Pending Order
Change Status = Processing
Perform Database Operations
Change Status = Completed
COMMITIf an operation fails:
ROLLBACKHowever, transactions should not normally be held open across slow external API calls. For distributed workflows, patterns such as idempotency, outbox/inbox, queues, and Saga may be more appropriate.
47. Windows Service + Message Queue
In a larger architecture, instead of polling SQL Server:
SQL Server
|
v
Windows Servicewe might use:
Web API
|
v
Azure Service Bus / RabbitMQ
|
v
Windows Service
|
v
Order ProcessorThe Worker waits for messages.
This is often better when work should be processed asynchronously and reliably.
48. Windows Service + Azure Service Bus
For example:
Customer
|
v
Web API
|
v
Azure Service Bus
|
v
Windows Service
|
v
Order ProcessingThe service can consume messages continuously.
Conceptually:
while (!stoppingToken.IsCancellationRequested)
{
var message =
await ReceiveMessageAsync(
stoppingToken);
await ProcessMessageAsync(
message,
stoppingToken);
}For enterprise systems, this approach can provide better decoupling than repeatedly querying the database.
49. Health Monitoring
Production Windows Services should be monitored.
Useful information includes:
Service Status
Last Successful Processing
Last Failure
Number of Records Processed
Processing Duration
Database Connectivity
External API AvailabilityFor example:
Order Processing Service
Status: Running
Orders Processed: 15,230
Last Successful Run:
2026-08-31 12:15:00
Last Error:
None
Average Processing Time:
1.8 seconds50. Configuration by Environment
Avoid hard-coding production settings.
Use:
appsettings.json
appsettings.Development.json
appsettings.Production.jsonExample:
{
"WorkerSettings": {
"IntervalSeconds": 30
}
}Development:
{
"WorkerSettings": {
"IntervalSeconds": 10
}
}Production:
{
"WorkerSettings": {
"IntervalSeconds": 60
}
}51. Security
Do not store passwords directly inside source code.
Bad:
var connectionString =
"Server=...;User Id=admin;Password=12345";Better approaches include:
Windows authentication where appropriate
Environment-specific configuration
Secret management
Azure Key Vault for Azure-hosted workloads
Restricted service accounts
The service should run with only the permissions it actually needs.
Avoid giving unnecessary administrator privileges.
52. Service Account
A Windows Service runs under an account.
Common options include:
Local System
Local Service
Network Service
Custom Service AccountFor production applications, use an appropriately restricted service identity rather than automatically granting broad privileges.
The identity should have only the permissions required for:
Database
File System
Network
APIs
Certificates
Logs53. File Access
If your service processes files:
C:\Input
C:\Output
C:\Archivemake sure the Windows Service account has appropriate permissions.
A common mistake is:
Console Application
|
v
Works perfectlybut:
Windows Service
|
v
Access DeniedWhy?
Because the console application and Windows Service may be running under different user accounts.
54. Current Directory Problem
When running interactively, developers sometimes use:
Directory.GetCurrentDirectory()But Windows Services may have a different working directory.
Prefer application-relative paths based on:
AppContext.BaseDirectoryMicrosoft's Windows Service hosting integration sets the content root appropriately when running as a Windows Service. (Microsoft Learn)
55. Deployment Process
A typical deployment process is:
Developer
|
v
Git Repository
|
v
CI/CD Pipeline
|
v
dotnet build
|
v
dotnet test
|
v
dotnet publish
|
v
Deployment Server
|
v
Stop Service
|
v
Copy New Version
|
v
Start Service
|
v
Verify LogsFor enterprise applications, this process can be automated using Azure DevOps or another CI/CD platform.
56. Updating the Service
Suppose version 1 is installed:
OrderProcessingService v1You release:
OrderProcessingService v2Typical deployment:
sc.exe stop "Order Processing Service"Deploy the new files.
Then:
sc.exe start "Order Processing Service"Always plan deployment carefully if the service is processing critical work.
57. Troubleshooting
Problem 1: Service doesn't start
Check:
Event ViewerAlso verify:
Executable path
Service account permissions
Configuration
Connection strings
Required files
.NET runtimeProblem 2: Service starts and immediately stops
Possible causes:
Unhandled exception
Invalid configuration
Missing dependency
Database connection failure
Invalid executable
Startup exceptionCheck Event Viewer and application logs.
Problem 3: Works with dotnet run but not as a service
Common reasons:
Different service account
File permission issue
Different working directory
Environment configuration
Missing configuration file
Database authentication
Network permissionsProblem 4: Database connection fails
Check:
SQL Server availability
Connection string
Authentication
Firewall
Service account permissions
Database permissionsProblem 5: Service keeps restarting
Check:
Event Viewer
Application logs
Service recovery configuration
Unhandled exceptions
Memory/CPU issues
External dependency failures58. Complete Architecture
A mature implementation might look like:
┌─────────────────────┐
│ Windows Server │
│ │
│ Service Control │
│ Manager │
└──────────┬──────────┘
│
▼
┌─────────────────────┐
│ Order Worker │
│ │
│ BackgroundService │
└──────────┬──────────┘
│
▼
┌─────────────────────┐
│ Order Processor │
│ │
│ Business Rules │
└───────┬───────┬─────┘
│ │
┌─────────┘ └─────────┐
▼ ▼
┌──────────────┐ ┌──────────────┐
│ SQL Server │ │ External API │
└──────────────┘ └──────────────┘
│
▼
┌───────────┐
│ Event Log │
└───────────┘59. End-to-End Flow
Let's summarize the entire application.
Step 1 — Windows starts
Windows ServerStep 2 — Service Control Manager starts the service
SCM
|
v
Order Processing ServiceStep 3 — .NET Host starts
Host
|
v
Dependency Injection
|
v
BackgroundServiceStep 4 — Worker starts
Worker.ExecuteAsync()Step 5 — Worker retrieves orders
SQL Server
|
v
Pending OrdersStep 6 — Business logic executes
OrderProcessorStep 7 — Database gets updated
Pending
|
v
Processing
|
v
CompletedStep 8 — Logging occurs
Event LogStep 9 — Worker waits
30 secondsStep 10 — Processing starts again
Process
|
v
Wait
|
v
Process
|
v
WaitStep 11 — Windows sends stop signal
CancellationTokenStep 12 — Worker exits gracefully
ExecuteAsync()
|
v
Host Shutdown
|
v
Service Stopped60. Complete Worker Example
Here is a simplified final version:
using Microsoft.Extensions.Hosting;
public class Worker : BackgroundService
{
private readonly IServiceScopeFactory _scopeFactory;
private readonly ILogger<Worker> _logger;
public Worker(
IServiceScopeFactory scopeFactory,
ILogger<Worker> logger)
{
_scopeFactory = scopeFactory;
_logger = logger;
}
protected override async Task ExecuteAsync(
CancellationToken stoppingToken)
{
_logger.LogInformation(
"Order Processing Service started.");
using var timer =
new PeriodicTimer(
TimeSpan.FromSeconds(30));
try
{
while (await timer.WaitForNextTickAsync(
stoppingToken))
{
try
{
using var scope =
_scopeFactory.CreateScope();
var processor =
scope.ServiceProvider
.GetRequiredService<IOrderProcessor>();
await processor.ProcessAsync(
stoppingToken);
}
catch (OperationCanceledException)
when (stoppingToken.IsCancellationRequested)
{
break;
}
catch (Exception ex)
{
_logger.LogError(
ex,
"Error occurred while processing orders.");
}
}
}
catch (OperationCanceledException)
when (stoppingToken.IsCancellationRequested)
{
// Expected during shutdown.
}
_logger.LogInformation(
"Order Processing Service stopped.");
}
}61. Complete Program Example
using Microsoft.Extensions.Hosting;
var builder = Host.CreateApplicationBuilder(args);
builder.Services.AddWindowsService(options =>
{
options.ServiceName = "Order Processing Service";
});
builder.Services.Configure<WorkerSettings>(
builder.Configuration.GetSection("WorkerSettings"));
var connectionString =
builder.Configuration.GetConnectionString(
"DefaultConnection");
builder.Services.AddSingleton(
new OrderRepository(connectionString!));
builder.Services.AddScoped<IOrderProcessor, OrderProcessor>();
builder.Services.AddHostedService<Worker>();
var host = builder.Build();
host.Run();62. Commands Cheat Sheet
Create project
dotnet new worker -n OrderProcessingServiceAdd Windows Service support
dotnet add package Microsoft.Extensions.Hosting.WindowsServicesBuild
dotnet buildRun locally
dotnet runPublish
dotnet publish -c Release -r win-x64 --self-contained true /p:PublishSingleFile=trueCreate service
sc.exe create "Order Processing Service" binPath= "C:\Services\OrderProcessingService\OrderProcessingService.exe"Configure automatic startup
sc.exe config "Order Processing Service" start= autoStart
sc.exe start "Order Processing Service"Stop
sc.exe stop "Order Processing Service"Delete
sc.exe delete "Order Processing Service"Check failure configuration
sc.exe qfailure "Order Processing Service"63. Best Practices
For production Windows Services, follow these practices:
Use
BackgroundService.Use Dependency Injection.
Use asynchronous APIs.
Pass
CancellationTokenthroughout the processing pipeline.Use structured logging.
Don't hard-code connection strings.
Use secure secret management.
Run using a least-privilege service account.
Configure service recovery.
Make processing idempotent.
Use database transactions where appropriate.
Avoid processing the same record twice.
Monitor service health.
Monitor CPU and memory.
Keep the Worker class thin.
Put business logic into separate services.
Use configuration for intervals and batch sizes.
Test the application as both a console application and Windows Service.
Automate deployment through CI/CD where practical.
Use a message broker when continuous database polling is no longer appropriate.
64. When Should You Use a Windows Service?
Windows Services are particularly useful when:
Continuous Background Processing
+
Windows Server Environment
+
No User Interaction RequiredExamples:
File Processing
Input Folder
|
v
Windows Service
|
v
Validate File
|
v
Process File
|
v
Archive FileOrder Processing
Database
|
v
Windows Service
|
v
Process OrdersData Synchronization
System A
|
v
Windows Service
|
v
System BScheduled Reports
Windows Service
|
v
Generate Report
|
v
Save PDF
|
v
Send Notification65. When Should You NOT Use a Windows Service?
A Windows Service may not be the best choice when:
The workload is already event-driven through a managed cloud messaging platform.
You need massive horizontal scaling.
The workload is better suited to serverless functions.
The application must expose HTTP endpoints as its primary responsibility.
The environment is Linux-only.
A managed cloud service can perform the same task more reliably.
For cloud-native systems, alternatives can include:
Azure Functions
Azure Container Apps
AKS
Azure Service Bus
Cloud-hosted Worker ServicesThe right choice depends on the workload and operational requirements.
66. Interview Questions
Q1. What is a Windows Service?
A Windows Service is a background application managed by the Windows Service Control Manager.
Q2. What is BackgroundService?
BackgroundService is a .NET base class used to implement long-running background tasks.
Q3. How do you convert a Worker Service into a Windows Service?
Install:
Microsoft.Extensions.Hosting.WindowsServicesand configure:
builder.Services.AddWindowsService();Q4. What is ExecuteAsync?
It is the main asynchronous method where the background work is implemented.
Q5. Why use CancellationToken?
It allows the worker to respond to shutdown requests gracefully.
Q6. How do you install a Windows Service?
Using:
sc.exe createQ7. How do you start it?
sc.exe startQ8. How do you stop it?
sc.exe stopQ9. How do you remove it?
sc.exe deleteQ10. Where can you check Windows Service errors?
Use:
Event Viewer
→ Windows Logs
→ ApplicationQ11. How do you automatically restart a failed service?
Configure Windows Service recovery actions using Service Control Manager settings or sc.exe failure.
Q12. How do you avoid duplicate processing?
Use techniques such as:
Idempotency
Status transitions
Database constraints
Transactions
Outbox/Inbox patterns
Message deduplicationdepending on the architecture.
67. Final Takeaway
A modern .NET Windows Service is not simply a program containing an infinite loop.
A production-quality implementation should have:
Windows Service
|
v
BackgroundService
|
v
Dependency Injection
|
v
Business Service
|
+---------+---------+
| |
v v
Database External API
| |
+---------+---------+
|
v
Logging
|
v
MonitoringThe most important concepts to remember are:
Worker Service
↓
BackgroundService
↓
ExecuteAsync()
↓
CancellationToken
↓
Dependency Injection
↓
Business Processing
↓
Logging
↓
Publish
↓
Windows Service
↓
Service Control Manager
↓
Recovery + MonitoringThis architecture provides a clean foundation for building background processing applications such as order processors, file processors, synchronization services, scheduled jobs, notification services, and enterprise integration services.
Conclusion
Windows Services continue to be useful for long-running background workloads on Windows servers.
With modern .NET, the preferred approach is to build the application using the Worker Service/BackgroundService model and then integrate it with Windows Service hosting.
The important distinction is:
BackgroundService implements the background work, while Windows Service hosting allows Windows to manage the application's lifecycle.
Once this foundation is understood, the same Worker Service concepts can be extended to SQL Server processing, REST APIs, Azure Service Bus, RabbitMQ, file processing, scheduled jobs, monitoring, and other enterprise workloads.
Official Microsoft references
If you want, I can next turn this into a professional blog thumbnail + architecture diagram, or convert the complete article into Telugu.

