This will be be a short post, and it's more of a public service announcement for something that's been out for a while; but Topshelf is so fantastic that it's worth giving it a mention, in case you haven't run into it yet.
If you're anything like me, when you have the need to create a Windows service to do some sort of background task, typically you just start off with a console application because it's super easy and super-easy to debug. Then after you finish working on the logic, you do a bunch of Googling (or copy and pasting) to figure out how to make a service. You also probably continue to have a way of running the code as a console application, for on-screen debug information and such.
Topshelf takes care of all of that for you. With minimal code changes I was able to take my console application and convert it into a service.
Take a look for yourself. Old code:
static void Main(string[] args)
{
StartMessagePump();
Console.Read();
}
New code:
static void Main(string[] args)
{
HostFactory.Run(x =>
{
x.Service<Program>(s =>
{
s.ConstructUsing(p => new Program());
s.WhenStarted(p => p.StartMessagePump(););
s.WhenStopped(p => Log("Shutting Down"));
});
x.RunAsLocalSystem();
x.SetDescription("Event Processor");
x.SetDisplayName("Event Processor");
x.SetServiceName("EventProcessor");
});
}
How easy was that?
Additional goodies include command line arguments that can be supplied to your application. For instance, to install on the server, with a delayed start, I'd use the following command (in an admin console):
EventProcessor.exe install --delayed
It's that easy. Topshelf is available as a Nuget package. Next time you need to create a Windows service, give it a spin!
Further Notes
The following has nothing to do with Topshelf, but I thought you might find it useful anyway. A Windows service must return control to the caller (the thing starting the service) in a timely fashion. If you don't (as was the case with me, my service has a while(true) loop), you will get the following error:
error 1053 the service did not respond to the start or control request in a timely fashion
The easiest solution to this is to introduce a timer to your startup code and have the blocking code kick off after a short time passes.
private void Init()
{
_timer.Elapsed += _timer_Elapsed;
_timer.Enabled = true;
}
private void _timer_Elapsed(object sender, ElapsedEventArgs e)
{
BeginProcessing();
_timer.Enabled = false;
}
So if you landed on this page after Googling "error 1053"... you're welcome!