Better Windows Services with TopShelf

August 30, 2018 3 minutes

Windows Services are programs that run on the background, often without without user interaction, and often without requiring a user login if we want. They have several uses, as for example:

  • Handling system events, e.g. when a new USB device is inserted, install its drivers; when a program requires elevated permissions, notify the user.
  • Run OWIN self-hosting for a lightweight alternative to IIS.
  • Message queue processing.
  • Health/heartbeat monitoring, e.g. call an API from time to time to check if it’s working properly.

And so on.

Advantages over a console application

If you’ve dealt with cases like the ones listed, you may have already deviced a solution where you just use a console application that does the job just ok, and that’s easily testable and maintainable.

However, this solution is not robust:

  • A console window can be closed by accident,
  • it has to be started manually (even with autorun, you still have to login as the user),
  • keep the user logged-in…
  • … and even then, if the program crashes you have to restart it manually.

Fortunately, services solve those problems and more:

  • Services are managed by the Service Control Manager (SCM) in the background, and to interact with them you have to explicitly use services.msc, sc.exe or PowerShell AND have the permissions to do so.
  • Services can start on boot, manually or due to a custom trigger, as for example when an USB is inserted, as mentioned earlier. No user login required.
  • Services run independently of the logged users. By default they can use any of the following system accounts:
    • Local System (default), a very powerful machine account. Comparable to running stuff as root in Linux.
    • Local Service, which as minimal system privileges and presents itself as anonymous in the network.
    • Network Service, which also has minimal privileges, but presents itself as the machine in the network.
  • Services can have auto-recovery policies, that go from restarting themselves on failure, up to the nuclear option of rebooting the whole system.

So, after hyping the idea of Windows services so much, how can we get started with them?

The old way - ServiceBase trickery

I’m going to be blunt here. I don’t remember how bad it’s to program, debug, and deploy services made with ServiceBase direcly. What I do know however is that I don’t want to repeat the experience.

You may want to investigate this further if you wish, or just take my word for now.

The new(er) way - TopShelf

Every programmer at some point learnt about making console applications. Printing “hello world” into the terminal, and things like that. You have to have a “main” entry point, and that’s it. If you want to run it, you can compile it and double-click the resulting .exe, and if you want to debug it in VS, you just put a breakpoint somewhere and press F5.

With TopShelf you can write console applications and install them as services. All you need is a class with a Start() and Stop() methods and some minimal configuration.

static void Main(string[] args)
{
    HostFactory.Run(serviceConfig =>
    {
        serviceConfig.Service<MyQtService>(serviceInstance =>
        {
            serviceInstance.ConstructUsing(() => new MyQtService());
            serviceInstance.WhenStarted(svc => svc.Start());
            serviceInstance.WhenStopped(svc => svc.Stop());
        });

        serviceConfig.SetServiceName("MyQtService");
        serviceConfig.SetDisplayName("My Qt Service");
        serviceConfig.SetDescription("A service that doesn't do anything...");

        serviceConfig.StartAutomatically();
    });
}

There’s also a quickstart at the documentation page.

Installation procedure

  • Compile the application with or without debug symbols.
  • Open an Administrator command prompt, and navigate to the output directory.
  • Run myservicename.exe install. Alternatively run myservicename.exe help to see all the available options.

Debugging an already installed service

Open the solution of the service we wish to debug, and attach to process as usual. Nothing special.

Summary

This was a introductory look into TopShelf, but complete enough to get started and to make something useful. For more information on the tool, check the official documentation, or Jason Roberts’ TopShelf course on Pluralsight.