A few weeks ago, I was tasked with creating a notification service to push notifications based on configurations retrieved from an Azure Service Bus Topic. Developing and testing the service in Visual Studio went smoothly — everything worked perfectly as expected.
However, the real challenge began after deploying the service to a Windows Server as a Windows Service. It stubbornly refused to start, repeatedly throwing Error 1053, as shown below:
The service did not respond to the start or control request in a timely fashion.
Trust me — my head was on fire! 😩 I had seen the service run flawlessly in Visual Studio, and I was quickly running out of time to deliver the task.
After extensive research, I discovered that Error 1053 can have multiple causes. The first step to diagnosing the issue is to check the Event Viewer under Windows Logs -> Application or System for detailed error messages.
In my case, the error log was:
The <Service Name> service failed to start due to the following error:
The service did not respond to the start or control request in a timely fashion.
Let’s delve right into how I resolved this…
What is A Worker Service?
A Worker Service is a long-running background service designed for tasks that do not require direct user interaction. It is ideal for scenarios where actions need to be performed continuously, at intervals, or in response to events, such as listening to message queues, processing data, or scheduling tasks. I like to think of it as a tool for automation — a “fire and forget” solution. It’s important to note that a Worker Service will not terminate unless explicitly instructed to do so.
The Problem
After building an excellent implementation of my task and testing it in Visual Studio, everything worked perfectly. My service ran as expected and didn’t terminate unless I explicitly stopped it via the console.
Hmm, the console… There’s a part I haven’t mentioned yet. Up until this project, I didn’t know anything about Worker Services, so I initially created the application as a Console application. To keep it running indefinitely, I used a simple trick: Console.ReadKey(). This kept the application alive until I pressed a key in the console.
However, when I deployed it as a Windows Service, I hit my first major issue: services can’t interact with the Console. As a result, the service failed to run. After much research and guidance from senior engineers, I realized I had two options:
- Instrument my current Console app as a Worker Service by adding a
Worker.csclass. - Create a new Worker Service project and migrate my existing solution.
Interestingly, I tried both approaches. For the sake of this write-up, I’ll walk you through how to create a Worker Service project and deploy it as a Windows Service.
A Windows Service cannot interact with the console…
Creating A Worker Service
Step 1: Open Visual Studio
- Launch Visual Studio (preferably 2019 or newer).
Step 2: Create a New Project
- Select Create a new project from the startup window.
- In the search bar, type Worker Service.
- Select Worker Service (.NET) from the results and click Next.
Step 3: Configure the Project
- Enter a Project Name (e.g.,
WorkerServiceTutorial). - Choose a Location to save your project.
- Optionally, provide a Solution Name.
- Click Next.
Notice the worker.cs in the solution explorer, that’s your guy…That’s the core component where the background task logic resides. It inherits from the BackgroundService class, which provides the necessary structure for creating long-running background tasks in .NET applications.
The ExecuteAsync method is where the core logic of the Worker Service resides, making it the entry point for your implementation. In the example shown, the conditional !stoppingToken.IsCancellationRequested ensures that the background service continues to run until a cancellation request is received (such as when the service is stopped).
What happens in this ExecuteAsync method is that, as long as no cancellation request is made, the service executes its tasks and waits for 1 second between executions (Task.Delay(1000)). This keeps the application alive without restarting the entire service every second; instead, it loops continuously within the same service instance.
You can always adjust the timer to suit your needs… And also in a production application you might want to pay attention to lifecycle i.e AddSingleton(), AddHosted(), AddTransient(), AddScoped()
You can optionally override the StopAsync method for clean up of resources.
A quick look at the Program.cs file shows that minimal configuration is required to set up a Worker Service. We simply need to:
- Create the application builder.
- Register the worker class as a hosted service using
AddHostedService<Worker>(). - Build the application and its dependencies.
- Call
Run()to start the service.
The call to .Run() triggers the execution of the ExecuteAsync method in the worker class, which ideally should contain the core logic for the background service.
If you run this application, you should see the logs from ExecuteAsync written to the console every second (or based on the time interval you set). Additionally, if you’ve overridden the StopAsync method, you’ll notice your cleanup process or logs being triggered when you explicitly stop the application by pressing Ctrl + C or closing the console window.
Since a Windows Service doesn’t interact with the console, you’ll need to configure your application to log to a file instead. This ensures that you can still capture and review your logs even when the service is running without a visible interface.
For my application, I also implemented observability using OpenTelemetry. Stay tuned for my upcoming article on integrating OpenTelemetry!
Deploying Your Application As A Service
Create a Precompiled Folder:
First, add a Precompiled folder in your solution directory. This folder will store the publish profile and contain the generated DLLs and executables.
Publish Your Project:
- Right-click on your project in Visual Studio and select Publish.
- Select Folder as the target and browse to select your Precompiled folder.
- Click Publish.
Verify the Output:
If the publishing is successful, you should see a confirmation screen and a bunch of DLLs and executable files generated in the Precompiled folder.
Create the Windows Service:
Open Command Prompt or Powershell with administrator privileges and run the following command to create your Windows Service:
sc.exe create "YourServiceName" binPath= "C:\Path\To\YourExecutable.exe" DisplayName= "Worker Service Tutorial" start= auto
Important Notes:
- Replace
"YourServiceName"with the desired name for your service. - For the
binPath, locate the.exefile in your Precompiled folder and copy the full path. Ensure that the path is correctly enclosed in double quotes. - The
DisplayNameis the name that will be shown onservices.mscwhich is where we manage our services - Add
start= autoif you want the Windows Service to start automatically on system boot.
Start The Windows Service
To start the service we would need to do the following
- click
windows + rthen typeservices.msc. You should see the screen below, scroll through the list for your newly created service display name, the services are ordered alphabetically. - Right click on the service and start
ooopsss, why wouldn’t the service start. It was running perfectly, when we ran in visual studio… what is wrong? these were the thoughts flowing through my mind. To troubleshoot this, you’ll need to open Event Viewer and under Windows logs check System or Application logs for the error causing the service to crash. In our case:
Resolving the Issue
To resolve the issue where the Windows Service refuses to start, we need to ensure that the Service Manager recognizes our Worker Service as a legitimate Windows service.
The Solution:
There’s a package we need to add to our Worker Service project:Microsoft.Extensions.Hosting.WindowsServices. This can be downloaded from Nuget Manager.
My Dilemma
In my case, I was deploying the service to a Windows Server, not my local device. My concern was:
💭 What happens if we move to a Linux server? Would my service become obsolete or simply refuse to start?
If you’re curious about how I resolved this challenge, feel free to ask in the chat section, and I’ll gladly share my solution! 😉
To resolve our problem, we would need to add this line of code to our program.cs, imagine struggling for days only to realize that all I needed to add was a line of code and my problems would be gone.
Focus on line 5, that is the important piece of code that puts you out of your miseries😂😂😂.
Next step is to republish your application, so that your .exe file can be updated with the changes and start the service.
If you got to this point you’re simply amazing. Creating a Windows Service from a Worker Service or Console App can be herculean and sometimes confusing but if you follow my guide in this tutorial it’ll be a lot less stressful. You can check the documentation for Windows Services and Worker Services to understand it better.
Don’t forget to hit the clap and follow button to be notified when I write about many more interesting topics.
You can connect with me on:
LinkedIn: linkedin.com/in/adebanjo-emmanuel/
Twitter or X: https://twitter.com/Deolamma
Stay Positive and Productive👌.
