This article walks you through the process of using a Worker Service to create a Windows Service using BackgroundService all while using .NET 6.0. This article is based off the Create a Windows Service using BackgroundService article by Microsoft.
To follow this guide, it’s expected that you have the .NET 6.0 SDK installed, are working on a Windows operating system, and are using the Visual Studio IDE.
Create the project
Start by creating a new project in Visual Studio, select the project type Worker Service and select Next.

On the next page specify a Project Name and select Next.

On the next page specify a Framework and select Create. Select .NET 6.0 as the Framework.

Configuring the project
Once you’ve created a Worker Service project it needs to be configured to be used as a Windows Service and the creation of a service class itself.
Install NuGet packages
Using the NuGet package manager, install the following packages:
- Microsoft.Extensions.Hosting
- Microsoft.Extensions.Hosting.WindowsServices
- Microsoft.Extensions.Http
After the installation ensure that your project file contains the following:
<ItemGroup> <PackageReference Include="Microsoft.Extensions.Hosting" Version="6.0.0" /> <PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="6.0.0" /> <PackageReference Include="Microsoft.Extensions.Http" Version="6.0.0" /> </ItemGroup>
Create your service class
The next step is to create your service. For this example, you’ll create a service called JokeService which will make an API call to get a joke and return it.
Enter the following code in the JokeService class within the Namespace brackets:
public class JokeService { private readonly HttpClient _httpClient; private readonly JsonSerializerOptions _options = new() { PropertyNameCaseInsensitive = true }; private const string JokeApiUrl = "https://karljoke.herokuapp.com/jokes/programming/random"; public JokeService(HttpClient httpClient) => _httpClient = httpClient; public async Task<string> GetJokeAsync() { try { // The API returns an array with a single entry. Joke[]? jokes = await _httpClient.GetFromJsonAsync<Joke[]>( JokeApiUrl, _options); Joke? joke = jokes?[0]; return joke is not null ? $"{joke.Setup}{Environment.NewLine}{joke.Punchline}" : "No joke here..."; } catch (Exception ex) { return $"That's not funny! {ex}"; } } } public record Joke(int Id, string Type, string Setup, string Punchline);
You will also need to include the following using statements at the top of the JokeService class:
using System.Net.Http.Json; using System.Text.Json;
Update the Worker class
Replace the contents within the Namespace brackets in the Worker class with the following code:
public class Worker : BackgroundService { private readonly JokeService _jokeService; private readonly ILogger<Worker> _logger; public Worker( JokeService jokeService, ILogger<Worker> logger) => (_jokeService, _logger) = (jokeService, logger); protected override async Task ExecuteAsync(CancellationToken stoppingToken) { while (!stoppingToken.IsCancellationRequested) { string joke = await _jokeService.GetJokeAsync(); _logger.LogWarning(joke); await Task.Delay(TimeSpan.FromMinutes(1), stoppingToken); } } }
In the code above the JokeService and ILogger are injected. In the ExecuteAsync method the JokeService is called, and the returned joke is then logged to the windows log event. This is repeated once every minute while the service is running.
Update the Program class
Inside the Program class replace the assignment of host with the following code:
IHost host = Host.CreateDefaultBuilder(args) .UseWindowsService(options => { options.ServiceName = ".NET Demo Service"; }) .ConfigureServices(services => { services.AddHostedService<Worker>(); services.AddHttpClient<JokeService>(); }) .Build();
The UseWindowsService extension configures the app to work as a Windows Service. Here the name of the service is set to .NET Demo Service. The hosted service is registered and the HttpClient is registered to the JokeService for dependency injection.
Publish the service
The first step to publishing your service is to update your project file. Inside the PropertyGroup element, add the following elements:
<OutputType>exe</OutputType> <PublishSingleFile>true</PublishSingleFile> <RuntimeIdentifier>win-x64</RuntimeIdentifier> <PlatformTarget>x64</PlatformTarget>
Next, right-click the project in the Solution Explorer and select Publish.

In the Publish window, for your Target, select Folder and then Next.

On the Location page leave everything as default and select Finish.
You’ll now be brought to the publish page, here you need to adjust a few more settings before publishing, select Show all settings.

A Profile Settings window will appear. Ensure that the settings match those in the screenshot below:

Once you’ve updated your Profile settings and confirmed the settings match the screenshot select Save to return to the publish page. Once back to the publish page select Publish to begin the process using the publish profile you just configured.

Your service will then be compiled and published to Target Location.
Create, Start, Validate, Stop, and Delete the service
Once you have a published service it’s time to create the service in Windows and start it. Here you’ll be guided through the process of doing just that, validating it works, and stopping the service.
Create the service
To create a service in Windows you’ll use the native Windows Service Control Manager’s create command. First step is to open a new PowerShell window as Administrator. Then you’ll want to enter the following command, note the path to your service is the path it was published to:
sc.exe create ".NET Demo Service" binpath="C:\Path\To\App.WindowsService.exe"
You should see some output indicating the service was successfully created.

Start the service
To start the service, navigate to the Services application by pressing the Windows Key and searching Services.
Once in the Services application find your service in the list. Once found right-click it and select Start. Your service will now start running.

Validate the service
After starting your service, you can validate it by pressing the Windows key and searching Event Viewer, select the Event Viewer application. In the Event Viewer, navigate to Windows Logs then Application. You should then see a Warning from your Demo Service.

You can double click the warning to view its contents and in this case view the joke that was returned.

Stop the service
To stop your service return to the Services application (Windows Key and search Services) and locate your service. Once your service has been found from the list, right-click it and select Stop.

Delete the service
To delete the service, open a PowerShell window as Administrator and enter the following command.
sc.exe delete ".NET Demo Service"
You’ll get an output confirming the service has been successfully deleted.

Debugging the service
To debug the service there’s a couple things that need to be done. If you try to debug the service normally (pressing F5) you’ll get the following error:

The reason for this error is because single file debugging currently isn’t supported and the service is set to compile to a single file. To get around this there are two steps, first is to update the project file.
<PublishSingleFile>true</PublishSingleFile>
<PublishSingleFile Condition="'$(Configuration)' == 'Release'">true</PublishSingleFile>
You can now use the Debug configuration and the service will not be compiled into a single file which will allow you to debug the service.
You can switch between configurations using the configuration dropdown.

Now you can drop a breakpoint and debug your service (press F5) if you’re on the Debug configuration.
