42

As in the following link, one can stop, start, and "stop, then start" a service using C# code.

http://www.csharp-examples.net/restart-windows-service/

I have baked a .NET service that does implement OnStart and OnStop. However, I need to implement a "smart restart" functionality which is more involved than just stopping and then starting. I need to keep the downtime to just a few seconds if that (but Stop + Start can take minutes in this case when done cleanly, and I must do it cleanly), and having some parts of the system available while others are rebooting/refreshing.

Long story short - before I jump into implementing this OnSmartRestart functionality, I want to make sure that there is a fairly easy way to invoke this call from another C# application.

This feature is important, but dangerous. I want to make it fairly hidden, somewhat secure, also keep it simple, and make sure that this has negligible effect on the performance of my Windows service while it is performing its regular chores and not rebooting.

If I have to poll for some file or open a port and spend too much CPU on doing that, it would not be a good solution. I also want to keep this AS SIMPLE AS POSSIBLE (sorry for repetition).

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Hamish Grubijan
  • 10,562
  • 23
  • 99
  • 147

2 Answers2

65

You can send "commands" to a service using ServiceController.ExecuteCommand:

const int SmartRestart = 222;

var service = new System.ServiceProcess.ServiceController("MyService");
service.ExecuteCommand(SmartRestart);
service.WaitForStatus(ServiceControllerStatus.Running, timeout);

You'll need to add a Reference to the System.ServiceProcess.dll assembly.

The service can react to the command by overriding ServiceBase.OnCustomCommand:

protected override void OnCustomCommand(int command)
{
    if (command == SmartRestart)
    {
        // ...
    }
}
Chris Moschini
  • 36,764
  • 19
  • 160
  • 190
dtb
  • 213,145
  • 36
  • 401
  • 431
  • 20
    Some extra info: the DOS SC.exe command can send these commands too, security permissions allowing...e.g. 'SC CONTROL YOURSERVICENAME 200' – Mesh Dec 13 '12 at 13:46
  • Adrian, how is it normally called using the command, if your method is an alternative? Is "200" in your command analogous to 222 in the source code above? – JustBeingHelpful Nov 24 '15 at 08:45
  • 1
    Note that this requires special permissions in a typical Server environment where your .Net app/site is running on its own, limited permissions user. You can solve that by giving that user the permission to send custom commands to just this one service using this method: http://i.imgur.com/tql3pUA.png http://superuser.com/a/315709/101698 – Chris Moschini Mar 23 '16 at 14:54
  • 6
    At first this didn't work for me. Then I figured out the command integer must be between 128 and 255... (as stated on the MSDN page). Save yourself a headache and keep this in mind. – brz Jun 14 '17 at 11:19
18

The usual means of communicating with external processes in windows are:

  1. Named pipes
  2. Sockets
  3. COM's GetObject to get a reference to an object and then calling its methods over the exposed interface.

The first two have been exposed as WCF so that is the way to go. Third one does not seem relevant to your situation and is old.

If you need to run your commands from the same machine you can use named pipes but hardening has made it very difficult and troublesome. Otherwise use WCF's TCP named binding.

Malachi
  • 3,205
  • 4
  • 29
  • 46
Aliostad
  • 80,612
  • 21
  • 160
  • 208
  • 3
    This answer is superior (and required) if you plan on sending parameters. – Sam Axe Sep 03 '13 at 00:49
  • In general, this answer seems superior for any case where you want to take commands from a "userland" app, which seems to be the case for the OP. Using a WCF service does not require mucking about with permissions, which may be safer and more convenient. There's also an [MSDN article on hosting WCF services from a Windows service](https://msdn.microsoft.com/en-us/library/ms733069). – ZX9 Nov 29 '16 at 15:43