Creating Windows Services In .NET Core – Part 2 – The “Topshelf” Way

This article is part of a series on creating Windows Services in .NET Core.

Part 1 – The “Microsoft” Way
Part 2 – The “Topshelf” Way


In our previous piece on creating Windows Services in .NET Core, we talked about how to do things the “Microsoft” way. What we found was that while it was simple to get up and running, it was much harder to debug our service. Infact I would say borderline impossible.

And that’s where Topshelf comes in. Topshelf is a .NET Standard library that takes a tonne of the hassle out of creating Windows Services in both .NET Framework and .NET Core. But rather than recite the sales pitch to you, let’s jump right in!

Setup

Similar to our “Microsoft” method, there is no Windows Service or Topshelf “Visual Studio Template”. We instead just create a regular old .NET Core console application.

Then from our Package Manager Console, we run the following to install the Topshelf libraries.

The Code

We essentially want to recreate our previous code sample to work with Topshelf. Here’s how we do that :

All rather simple.

We inherit from the “ServiceControl” class (Which isn’t actually needed but it just provides a good base for us to work off). We have to implement the two methods to start and stop, and we just log those methods as we did before.

In our Main method of program.cs, it’s actually really easy. We can just use the HostFactory.Run method to kick off our service with minimal effort :

Crazy simple. But that’s not the only thing HostFactory can do, for example I may want to say that when my service crashes, I want to restart the service after 10 seconds, give it a nicer name, and set it to start automatically.

I could go on and on but just take a look through the Topshelf documentation for some configuration options. Essentially anything you would normally have to painfully do through the windows command line, you can set in code : https://topshelf.readthedocs.io/en/latest/configuration/config_api.html

Deploying Our Service

Same as before, we need to publish our app specifically for a Windows environment. From a command prompt, in your project directory, run the following :

Now we can check out the output directory at bin\Release\netcoreappX.X\win-x64\publish and we should find that we have a nice little exe waiting for us to be installed.

Previously we would use typical SC windows commands to install our service, but Topshelf utilizes it’s own command line parameters for installing as a service. Almost all configuration that you can do in code you can also do from the command line (Like setting recovery options, service name/description etc). You can check out the full documentation here :

For us, we are just going to do a bog standard simple install. So in our output directory, I’m going to run the following from the command line : http://docs.topshelf-project.com/en/latest/overview/commandline.html

Where WindowsServiceExample.exe is my project output. All going well my service should be installed! I often find that even when setting the service to startup automatically, it doesn’t always happen. We can actually start the service from the command line after installation by running :

In deployment scenarios I often find I have to install the service, wait 10 seconds, then attempt to start it using the above and we are away laughing.

Debugging Our Service

So when doing things the “Microsoft” way, we ran into issues around debugging. Mostly that we had to either use command line flags, #IF DEBUG directives, or config values to first work out if we are even running inside a service or not. And then find hacky ways to try and emulate the service from a console app.

Well, that’s what Topshelf is for!

If we have our code open in Visual Studio and we just start debugging (e.g. Press F5), it actually emulates starting the service in a console window. We should be met with a message saying :

This does exactly what it says on the tin. It’s started our “service” and runs it in the background as if it was running as a Windows Service. We can set breakpoints as per normal and it will basically follow the same flow as if it was installed normally.

We can hit Ctrl+C and it will close our application, but not before running our “Stop” method of our service, allowing us to also debug our shutdown procedure if required. Compared to debug directives and config flags, this is a hell of a lot easier!

There is just one single gotcha to look out for. if you get a message similar to the following :

This means that the service you are trying to debug in Visual Studio is actually installed and running as a Windows Service on the same PC. If you stop the Windows Service from running (You don’t have to uninstall, just stop it), then you can debug as normal.

What’s Next

A helpful reader pointed out in the previous article that .NET Core actually has a completely different way of running Windows Services. It essentially utilizes the “Hosted Services” model that has been introduced into ASP.NET Core and allows them to run as Windows Services which is pretty nifty!

ENJOY THIS POST?
Join over 3.000 subscribers who are receiving our weekly post digest, a roundup of this weeks blog posts.
We hate spam. Your email address will not be sold or shared with anyone else.

Leave a Reply

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