How to create and configure a Windows service with Topshelf and Ninject?
This article aims to present how it is possible to easily create and configure a Windows service with Topshelf and Ninject using dependency injection.
Topshelf NuGet is a package for encapsulating a classic console application in a Windows Service.
Ninject is also a NuGet package is container IOC to implement dependency injection.
Step 1, create a console application project and download packages via the management console :
PM > Install-Package Topshelf
PM > Install-Package Topshelf.Ninject
Step 2, define / service(s) interface(s) and the implement service to what the windows service depends on :
namespace TopShelfWindowsService.Services { public interface IMyService { void DoWork(); } }
public class MyService : IMyService { public void DoWork() { //Do something } }
Step 3, implement a module inheriting from “ModuleNinject” in order to register the concrete classes implementing interfaces used for injection
I recommend the lifecycle Singleton for objects, here is how to declare them when recording classes :
using Ninject.Modules; using TopShelfWindowsService.Services; namespace TopShelfWindowsService { public class IocModule : NinjectModule { // Bind Interfaces to implementations for dependancy injection public override void Load() { Bind<IMyService>().To<MyService>().InSingletonScope(); } } }
Step 4, implement the windows service deriving from the “ServiceControl” interface in the namespace “Topshelf”
I also propose an implementation of a timer that allows to execute a service all X seconds, while ensuring executes only one service at a time, through the static class “Monitor”.
By implementing the “ServiceControl” interface, it’s mandatory to implement the methods “Start” and “Stop”
using System.Threading; using System.Timers; using Topshelf; using TopShelfWindowsService.Services; using Timer = System.Timers.Timer; namespace TopShelfWindowsService { public class MyWindowsService : ServiceControl { private Timer _syncTimer; private static object s_lock = new object(); private IMyService _myservice; // Constructor public MyWindowsService(IMyService myService) { _myservice = myService; } // Starts the windows service public bool Start(HostControl hostControl) { _syncTimer = new Timer(); _syncTimer.Interval = 5000; _syncTimer.Enabled = true; _syncTimer.Elapsed += RunJob; return true; } // Stops the windows service public bool Stop(HostControl hostControl) { _syncTimer.Enabled = false; return true; } // Job runner event, with lock if the job still running private void RunJob(object state, ElapsedEventArgs elapsedEventArgs) { // Prevents the job firing until it finishes its job if (Monitor.TryEnter(s_lock)) { try { _myservice.DoWork(); } finally { // unlock the job Monitor.Exit(s_lock); } } } } }
Step 5, implement the entry point at the start of the windows service in a console application through Topshelf : Here we will set the use Ninject for dependency injection, and the name of windows service, description ….
using Topshelf; using Topshelf.Ninject; namespace TopShelfWindowsService { class Program { static void Main(string[] args) { HostFactory.Run(x => { x.UseNinject(new IocModule()); x.Service(s => { s.ConstructUsingNinject(); s.WhenStarted((service, hostControl) => service.Start(hostControl)); s.WhenStopped((service, hostControl) => service.Stop(hostControl)); }); x.RunAsLocalSystem(); x.SetDescription("Prototype .NET TopShelf Windows Service"); x.SetDisplayName("Prototype_TopShelf_and_Ninject"); x.SetServiceName("Prototype_TopShelf_and_Ninject"); }); } } }
Step 6, deploy the windows service :
Once the windows service is functional, move it (the config file, dlls and exe generated at compile time) to a directory on your machine.
Then, in the command line, go to the directory that contains dlls and then run the install as follow :
nom_de_l_executable.exe install
Start it as follow :
nom_de_l_executable.exe start
You can also stop the service and uninstall it :
nom_de_l_executable.exe stop
nom_de_l_executable.exe uninstall
Samples :