Creating a C# Windows Service

Microsoft Windows services, formerly known as NT services, enable you to create long-running executable applications that run in their own Windows sessions. These services can be automatically started when the computer boots, can be paused and restarted, and do not show any user interface. These features make services ideal for use on a server or whenever you need long-running functionality that does not interfere with other users who are working on the same computer.

You can check all windows services which already running on your Windows device from Windows Task Manager. You’re right, there are a lot of them.
As you noticed some of them are running continuously some others are stopped.
Today I will show you how to create your own simple Windows Service using a Topshelf library which is well documented, so we can achieve that in few simple steps.

Create new console application project.

namespace RadekKodujeService
{
    class Program
    {
        static void Main(string[] args)
        {
        }
    }
}

Then you have to install Topshelf library through Nuget Package Console tool.

nuget Install-Package Topshelf

The simplest implementation is presented below:

namespace RadekKodujeService
{
    class Program
    {
        static void Main(string[] args)
        {
            HostFactory.Run(z =>
            {
                z.Service<ServiceCore>(s =>
                {
                    s.ConstructUsing(c =>  new ServiceCore());
                    s.WhenStarted(c => c.Start());
                    s.WhenStopped(c => c.Stop());
                });
                z.RunAsLocalSystem();
                z.StartAutomatically();
                z.SetDescription("Test service for radekkoduje.pl");
            });
        }
    }
}

We only need a class which will be a core of our service.

    public class ServiceCore
    {
        public void Start()
        {
            Console.WriteLine("Service started");
        }

        public void Stop()
        {
            Console.WriteLine("Service stopped");
        }
    }

It is done! As you can see service was started.

Service installation is as simple as implementation. Because we want to check status of running service, we have to add writing to text file feature to our main class.

    public class ServiceCore
    {
        private Timer timer;

        public ServiceCore()
        {
            timer = new Timer(1000);
            timer.Elapsed += (sender, args) =>
            {
                string message = string.Format(
                    "{0} - I am still working!{1}",
                    DateTime.Now.ToString(), 
                    Environment.NewLine);

                File.AppendAllText("test.txt", message);
            };
        }

        public void Start()
        {
            Console.WriteLine("Service started");
            timer.Start();
        }

        public void Stop()
        {
            Console.WriteLine("Service stopped");
            timer.Stop();
        }
    }

For installation, we have to use CLI in administrator mode. Execute install command on created service .exe file.
Without TopShelf library we would have to use installation tool Installutil.exe

As you can see installation succeeded.

It’s working 🙂

The main adventage of presented library is improved speed of development and simplification. You can also debug service application created in that way without any problems. In classical windows service the only way for debuging is to use Environment.UserInteractive and create service core object manually.

Topshelf has large amount of useful plugins. You can integrate it with:

  • loggers:
    • NLog
    • Log4Net
    • Serilog
  • IoC containers:
    • Autofac
    • Unity
    • CastleWindor
    • SimpleInjector
    • Ninject

Example of implementation using Unity IoC container:

                HostFactory.Run(x =>
                {
                    x.UseUnityContainer(container);
                    x.Service<ServiceCore>(s =>
                    {
                        s.ConstructUsingUnityContainer();
                        s.WhenStarted(sc => sc.Start());
                        s.WhenStopped(sc => sc.Stop());
                    });
                    x.RunAsLocalSystem();
                    x.StartManually();
                });

and Ninject:

                HostFactory.Run(x =>
                {
                    x.UseNinject(new Bindings());  // the Bindings is derived class from NinjectModule
                    x.Service<ServiceCore>(s =>
                    {
                        s.ConstructUsingNinject();
                        s.WhenStarted(a => a.Start());
                        s.WhenStopped(a => a.Stop());
                    });
                    x.RunAsLocalSystem();
                    x.StartManually();
                });

We can also execute previously scheduled actions by using additional library Quartz.NET.

                string expression = "0 0 12 1/1 * ? *";

                HostFactory.Run(x =>
                {
                    x.UseNinject(new Bindings());
                    x.Service<ServiceCore>(s =>
                    {
                        s.ConstructUsingNinject();
                        s.WhenStarted(a => a.Start());
                        s.WhenStopped(a => a.Stop());
                        s.UseQuartzNinject();
                        s.ScheduleQuartzJob(q => q.WithJob(() =>
                                            JobBuilder.Create<WriteToFileJob>() // the WriteToFileJob is class which implements IJob interface
                                            .Build())
                                            .AddTrigger(() => TriggerBuilder.Create().WithCronSchedule(expression).Build())
                                                );
                    });
                    x.RunAsLocalSystem();
                    x.StartManually();

There is a lot of possibilities. Thanks to libraries like this one, developer’s life is easier.
Your turn, create your first Windows Service.
May the force be with you 🙂

Leave a Reply

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