Image for post
Image for post

Introduction to Worker Services in .NET Core 3.0

Nick Fane
Nick Fane
Jun 12, 2019 · 6 min read

.NET Core 3 is on the horizon and with it comes a plethora of new features, one of which is a new project template for .NET Core Worker Services.

Before we begin, be aware that it’s been possible to create these services since .NET Core 2.1 using IHostedService, this release only adds the project template and minor refinements. However, since this appears to be a bit of a milestone in .NET Core and background workers, I thought I’d write up a few articles for those who haven’t yet worked with them and wanted to dive in.

About myself, I’ve been working with .NET for about six years now and through either luck or good fortune, have been able to build many production applications with .NET and ASP.NET Core since the initial stable release.

As much fun as it’s been, one of the most frustrating experiences has been creating background workers or windows services before .NET Core 2.1. In a previous company, we used the framework Topshelf (albeit as a means of running these workers as windows services), but they were building support for when .NET Core hit 2.0. Other frameworks such as Hangfire could have been used to reach our desired outcome, but with the continually changing landscape of .NET Core 1.x and Docker on the rise, we decided to go with regular old .NET Core Console applications running in containers.

While this approach worked well for us at the time, it always felt hacky and in my opinion, never gave .NET a strong argument for being the ‘right tool for the job’ when it came to creating these types of services.

Worker services aren’t anything new or revolutionary. If you’ve written software for any amount of time, chances are you’ve knowingly (or unknowingly) created many yourself! If you’ve ever written something as simple as a long-running console application or had a thread in an API pulling off a queue or shared resource, then you’ve pretty much built your own.

Worker services are the perfect use case for any background processing such as components in an ETL pipeline, processing messages from a Kafka, Rabbit or SQS queue. Perhaps you want to run customised health checks on your systems. Any processing job you can think of where you need a simple, straightforward framework to do so, Worker Services now has you covered.

Nowadays it’s a breeze to build these services, to follow this guide, go ahead and download the .NET Core 3.0 Preview as well as the Visual Studio Preview to begin using it (or enable previews in your current Visual Studio, whatever best suits you).

Image for post
Image for post

You can bootstrap a new project by going File > New Project > ASP.NET Core Web Application (which contains the Worker Service template while .NET Core 3.0 is in preview), creating your service then choosing the Worker Service template from the list

The first thing you’ll notice is that the template is as minimal as possible with only three files (or four if you’ve added Docker support), so if you’re like me and hate having tons of bootstrapping files in your project templates, then you’ll love it.

Image for post
Image for post
Pretty damn minimal

If you’ve been around .NET Core for a while, the program.cs file should be pretty straightforward, but if not, then here’s a quick explanation.

Image for post
Image for post

In short, we have two methods, Main which is the entry point to our application, passing in any additional arguments to our runtime and CreateHostBuilder which will bootstrap our application, configure our services and setup any dependencies that we need.

The CreateHostBuilder is where you can add your configuration management, IoC or any additional startup configuration you may need.

You will notice the template has already provided an example of a basic worker service, with IoC and it’s own managed lifecycle.

Image for post
Image for post
Default worker with IoC and a lifecycle.

The template utilises IoC to inject a logger into our service and manages its lifecycle via a CancellationToken that’s passed in by the .NET Core framework. Most worker services wouldn’t differ too much from this implementation unless of course, you were using an external source (i.e. feature flag) to handle the lifecycle.

These workers can be run in the same fashion that you’d run a Console Application (or most .NET Core applications), use the .NET Core CLI, publish the solution/project and call dotnet run on the DLL that is produced by your project. You can run it in a container by adding an appropriate Docker file and running docker build and docker run on the file.

Running the service in a container is the same as running any other .NET Core applications. If you’ve added Docker support (in my case I chose Windows containers) when you started your project you’ll be created with a Dockerfile similar to the one below.

Image for post
Image for post
Dockerfile for Windows containers

At first it may seem like a lot of steps, but the breakdown is quite simple. We start by pulling a nanoserver runtime image to that we’ll use when we run our container and use the alias base.

Next, we pull from the SDK equivalent of that nanoserver image so we have access to the .NET Core SDK. We choose our WORKDIR, copy our project files into it, then run our dotnet restore and build commands.

We then dotnet publish our application’s DLL’s in a release configuration to the /app directory of our build image. Lastly, we come back to our base image, and copy our published DLL’s into the /app directory of the base image and assign the ENTRYPOINT so docker knows how to run our application.

If you’re looking to run as a Windows service, you’ll need to configure the template slightly.

Start by downloading the Microsoft.Extensions.Hosting.WindowsServices NuGet package and adding it to your project

Image for post
Image for post
The current (3.0.0.5) preview package for hosting Windows Services

Now inside your program.cs add UseWindowsService() to your CreateHostBuilder

Image for post
Image for post

Now we can create a service by running a dotnet publish on our project, then use the sc.exe utility to create a service. Here’s a batch script I’d include in my projects to automate this

dotnet restore
dotnet publish -c Release -o ./publish/workerservice
sc.exe create MyWorkerService binpath= ./publish/workerservice/worker-preview.exe

Image for post
Image for post
Run this from the projects root directory

And if all goes well, You should see your Windows Service created and runnable from the service manager!

Image for post
Image for post
Image for post
Image for post
The worker service waiting to run

Awesome! If all went well, you should be ready to build some Worker Services using .NET Core 3. If you’ve learnt something from this tutorial, please share it with anyone you think could use this information! Stay tuned for further tutorials on .NET Core Worker Services and thanks for reading!

Queue Processing with .NET Core Worker Services

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch

Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore

Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store