Topshelf for windows services

26. september 2015

Topshelf for windows services

I recently came across this library and instantly fell in love with it's simplicity. If you are looking for an easy way to make windows services, topshelf is definitely for you.

In this post I'll give a quick tour of what topshelf does. Check out the official topshelf page here. It's also open source and you can find the code on github.

I'll cover these topics:

 

Getting started

Open visual studio and create a new console application project.

namespace TopShelfService.Console
{
    class Program
    {
        static void Main(string[] args)
        {
            
        }
    }
}

 

Next, install the topshelf nuget package either from the console or the nuget manager.

 

Setting up the service

Now we'll make a class that serves as the interface between the windows service and your own code. We need to execute our code when the service starts and when the service stops.

Add a class called Application with to voids, Start() and Stop().

namespace TopShelfService.Console
{
    public class Application
    {
        public Application()
        {            
        }

        public void Start()
        {            
        }

        public void Stop()
        {            
        }
    }
}

Now we need to register this class into topshelf. This is done in the console Main method.

using Topshelf;
namespace TopShelfService.Console
{
    class Program
    {
        static void Main(string[] args)
        {
            HostFactory.Run(x =>
            {
                x.Service<Application>(s =>
                {
                    s.ConstructUsing(n => new Application());
                    s.WhenStarted(service => service.Start());
                    s.WhenStopped(service => service.Stop());
                });
            });
        }
    }
}

A few things going on here. We're telling tophelf to look at our Application class. We're also telling it how to contruct this class. If you'r using dependency injection this is where you want to take care of it. We are also telling topshelf what to do when the service is started and stopped.
Very easy and quite neet. 

 

Running locally

In order to run your project locally, simply hit F5 as you are used to.

This simply starts your console application with some output that should look something like this. To quit, hit Ctrl+C.

Topshelf for windows services console application

 

Install and uninstall

You're ready to deploy your service - Great!

Once you have compiled your code, open a command prompt with administrator rights and type the name of your .exe file followed by a space and "install".

Topshelf console demo install

You should be prompted with either a success or an error message. In my experience, Topshelf is pretty good at telling you what went wrong if something went wrong during installation.

If the installation was successful, open your local service manager and locate your brand new service.

Topshelf installed service

To uninstall, simply run the same command line but with "uninstall" instead of "install".

Setting service name and description

You probably want to set a service name different from the executable exe file. In order to do this, add a few lines in your console main method.

using Topshelf;
namespace TopShelfService.Console
{
    class Program
    {
        static void Main(string[] args)
        {
            HostFactory.Run(x =>
            {
                x.Service<Application>(s =>
                {
                    x.SetServiceName("TopshelfServiceTest");
                    x.SetDescription("Topshelf Service description");
                    x.SetDisplayName("Topshelf display name");
                    s.ConstructUsing(n => new Application());
                    s.WhenStarted(service => service.Start());
                    s.WhenStopped(service => service.Stop());
                });
            });
        }
    }
}

The method names pretty much says it all. Note that SetServiceName(...) only takes strings with no white space. On order to give it a pretty name, use SetDisplayName(...). 

Setting startup mode and run-as account

In order to set startup mode you can choose between StartManually(), StartAutomatically() og StartAutomaticallyDelayed() which reflects the posibilities when editing a windows service manually. It's also possible to set a startup timeout using the SetStartTimeout(...) method.

Setting the run-as account comes with a few built in options. .RunAsLocalService(), .RunAsLocalSystem(), .RunAsNetworkService, .RunAsPrompt() or if you want to use custom credentials .RunAs(username, password).

using Topshelf;
namespace TopShelfService.Console
{
    class Program
    {
        static void Main(string[] args)
        {
            HostFactory.Run(x =>
            {
                x.Service<Application>(s =>
                {
                    x.SetServiceName("TopshelfServiceTest");
                    x.SetDescription("Topshelf Service description");
                    x.SetDisplayName("Topshelf display name");
                    s.ConstructUsing(n => new Application());
                    s.WhenStarted(service => service.Start());
                    s.WhenStopped(service => service.Stop());
                });
                x.StartManually();
                x.RunAsLocalService();
            });
        }
    }
}

 

Threading

It's worth noting that topshelf executes your code on the service main thread - Which is a good thing as you don't want a library like this to do all kinds of hidden threading stuff. But it means that if your application hangs or does a busy spin i a loop, the service will be unresponsive if you try to stop it via the service manager. You will have to kill it in the task manager.