This article is part of a series on creating Windows Services in .NET Core.
This article has been a long time coming I know. I first wrote about creating Windows Services in .NET Core all the way back in September (3 months ago). And on that post a helpful reader (Shout out to Saeid!) immediately commented that in .NET Core 3, there is a brand new way to create Windows Services! Doh! It reminds me of the time I did my 5 part series on Azure Webjobs in .NET Core, and right as I was completing the final article, a new version of the SDK got released with a tonne of breaking changes making me have to rewrite a bunch.
Thankfully, this isn’t necessarily a “breaking change” to how you create Windows Services, the previous articles on doing it the “Microsoft Way” and the “Topshelf Way” are still valid, but this is just another way to get the same result (Maybe with a little less cursing to the programming gods).
The first thing you need to know is that you need .NET Core 3.0 installed. At the time of writing, .NET Core 3.1 has just shipped and Visual Studio should be prompting you to update anyway. But if you are trying to do this in a .NET Core 2.X project, it’s not going to work.
If you like creating projects from the command line, you need to create a new project as the type “worker” :
dotnet new worker
If you are a Visual Studio person like me, then there is actually a template inside Visual Studio that does the exact same thing.
Doing this creates a project with essentially two files. You will have your program.cs which is basically the “bootstrapper” for your app. And then you have something called worker.cs which is where the logic for your service goes.
It should be fairly easy to spot, but to add extra background services to this program to run in parallel, you just need to create a new class that inherits from BackgroundService :
public class MyNewBackgroundWorker : BackgroundService
protected override Task ExecuteAsync(CancellationToken stoppingToken)
Then in our program.cs file, we just add the worker to our service collection :
.ConfigureServices((hostContext, services) =>
AddHostedService has actually been in the framework for quite some time as a “background service” type task runner that typically runs underneath your web application. We’ve actually done an article on hosted services in ASP.NET Core before, but in this case, the hosted service is basically the entire app rather than it being something that runs behind the scenes of your web app.
Running/Debugging Our Application
Out of the box, the worker template has a background service that just pumps out the datetime to the the console window. Let’s just press F5 on a brand new app and see what we get.
Worker running at: 12/07/2019 08:20:30 +13:00
Application started. Press Ctrl+C to shut down.
We are up and running immediately! We can leave our console window open to debug the application, or close the window to exit. Compared to the hell we went through trying to debug our Windows Service when creating it the “Microsoft” way, this is like heaven.
Another thing to note is that really what we have infront of us is a platform for writing console applications. In the end we are only writing out the time to the console window, but we are also doing that via Dependency Injection creating a hosted worker. We can use this DI container to also inject in repositories, set environments, read configuration etc.
The one thing it’s not yet is a windows service…
Turning Our App Into A Windows Service
We need to add the following package to our app :
Next, head to our program.cs file and modify it by adding a call to “UseWindowsService()”.
public static IHostBuilder CreateHostBuilder(string args) =>
.ConfigureServices((hostContext, services) =>
And that’s it!
Running our application normally is just the same and everything functions as it was. The big difference is that we can now install everything as a service.
To do that, first we need to publish our application. In the project directory we run :
dotnet publish -r win-x64 -c Release
Note in my case, I’m publishing for Windows X64 which generally is going to be the case when deploying a Windows service.
Then all we need to do is run the standard Windows Service installer. This isn’t .NET Core specific but is instead part of Windows :
sc create TestService BinPath=C:\full\path\to\publish\dir\WindowsServiceExample.exe
As always, the other commands available to you (including starting your service) are :
sc start TestService
sc stop TestService
sc delete TestService
And checking our services panel :
Installing On Linux
To be honest, I don’t have a hell of a lot of experience with Linux. But the general gist is…
Instead of installing Microsoft.Extensions.Hosting.WindowsServices , you need to install Microsoft.Extensions.Hosting.Systemd . And then instead of calling UseWindowsService() you’ll instead call UseSystemd() .
Obviously your dotnet publish and installation commands will vary, but more or less you can create a “Windows Service” that will also run on Linux!
Microsoft vs Topshelf vs .NET Core Workers
So we’ve now gone over 3 different ways to create Windows Services. You’re probably sitting there going “Well… Which one should I chose?”. Immediately, let’s bin the first Microsoft old school way of going things. It’s hellacious to debug and really doesn’t have anything going for it.
That leaves us with Topshelf and .NET Core workers. In my opinion, I like .NET Core Workers for fitting effortlessly into the .NET Core ecosystem. If you’re already developing in ASP.NET Core, then everything just makes sense creating a worker. On top of that, when you create a BackgroundService, you can actually lift and shift that to run inside an ASP.NET Core website at any point which is super handy. The one downside is the installation. Having to use SC commands can be incredibly frustrating at times and Topshelf definitely has it beat there.
Topshelf in general is very user friendly and has the best installation process for Windows Services. But it’s also another library to add to your list and another “framework” to learn, which counts against it.
Topshelf or .NET Core Workers, take your pick really.