.NET Core Worker Service

A year or so ago I wrote the post Host ASP.NET Core Application as a Windows Service. With the upcoming release of .NET Core 3, we now have another option for creating a service with the new Worker Service template. This post is going to walk through creating a new application using the new Worker Service template and then running the service as a Windows Service.

Project Creation

I’m going to use Visual Studio 2019 Preview for this process. If you would rather you can use the .NET CLI with the following command to create the project instead.

dotnet new worker

For the Visual Studio, open the application and select the Create a new project option.

On the next screen search for Worker Service and click Next.

On the next screen enter a Project name and click the Create button.

Next, click the create button to finally create the project, unless you want to use Docker.

Project Structure

The resulting structure is pretty simple. The two files that we will be dealing with are Program.cs and Worker.cs.

Program.cs is the entry point for the application and defines the different works you want to run. The following is an example that sets up two different workers. The default template only has one worker, but I added the second one to show multiple workers are an option.

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureServices((hostContext, services) =>
            {
                services.AddHostedService<Worker>();
                services.AddHostedService<Worker2>();
            });
}

Worker.cs contains the code that gets called to execute work. The following is the default worker that gets created from the template. This worker just writes a log once a second.

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);
        }
    }
}

At this point, you could run the application and it would do whatever work you have it set up to perform.

Run as a Windows Service

To run the project as a Windows Service we need to add a NuGet package. To do this right-click on the project file and select Manage NuGet Packages.

In the NuGet dialog click the Browse tab, check the Include prerelease checkbox, search for Microsoft.Extensions.Hosting.WindowsServices, and finally click Install.

After the package is installed open Program.cs and add a call to UseWindowsService to host builder in the CreateHostBuilder function.

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .UseWindowsService()
        .ConfigureServices((hostContext, services) =>
        {
            services.AddHostedService<Worker>();
            services.AddHostedService<Worker2>();
        });

Publish the Application

Now that we have the application set up to be able to run as a Windows service we need to publish it. To publish from the .NET CLI you can use the following command in the directory with the solution or project file. There is also an option for an output location if you want it to go to a different directory.

dotnet publish

Or from Visual Studio click the Build > Publish {Solution Name} menu. Select the Folder option on the left and then click Create Profile.

On the next screen click the Publish button.

Service Installation and Management

At this point, the application can be installed and managed like any other Windows service. To install the service open a command prompt in admin mode and run the following command to create a windows service. The binPath needs to be the full path to your exe or your service will fail to start even it is created successfully.

sc create WindowsServiceHosted binPath= "C:\Users\eanderson\Desktop\Worker\Worker\bin\Debug\netcoreapp3.0\publish\Worker.exe"

Also, note that the space after binPath= and before the exe name is needed.

Now that the service is installed run the following command to start it.

sc start Worker

To check the state of your service use the following command.

sc query Worker

To stop your service use the following command.

sc stop Worker

Finally, to uninstall your service use the following command.

sc delete Worker

Wrapping Up

This template makes it really easy to get started with a worker. Hopefully, this will help you get started. Make sure and check out the .NET Core Workers as Windows Services post from Microsoft.


Also published on Medium.

8 thoughts on “.NET Core Worker Service”

  1. You don’t happen to know if there is an easy way to have your service run batch jobs on some schedule do you. I have a Windows service that uses Quartz. Net and a cron syntax under the covers and would love to port it over to. Net Core 3.

    1. You use the override of BackgroundService like the ExecuteAsync but with this signature:

      public override Task StartAsync(CancellationToken cancellationToken)
      {
          sitesToMonitor = db.websitesToMonitor.OrderBy(p => p.Priority).ToList();
          httpClient = new HttpClient();
          return base.StartAsync(cancellationToken);
      }
      
      public override Task StopAsync(CancellationToken cancellationToken)
      {
          httpClient.Dispose();
          return base.StopAsync(cancellationToken);
      }
      
        1. Please rename “Worker” in the command to “WindowsServiceHosted”, I faced the same problem. As you can clearly see in commands, the service is created in the name of WindowsServiceHosted but is being called as Worker.

Leave a Reply to Jeff Cancel Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.