How to send a custom command to a .NET windows Service from .NET code?

32,936

Solution 1

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)
    {
        // ...
    }
}

Solution 2

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.

Share:
32,936
Hamish Grubijan
Author by

Hamish Grubijan

I GIVE PLENTY OF BOUNTY. CHECK OUT MY Qs!

Updated on July 09, 2022

Comments

  • Hamish Grubijan
    Hamish Grubijan almost 2 years

    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).

  • Mesh
    Mesh over 11 years
    Some extra info: the DOS SC.exe command can send these commands too, security permissions allowing...e.g. 'SC CONTROL YOURSERVICENAME 200'
  • Sam Axe
    Sam Axe over 10 years
    This answer is superior (and required) if you plan on sending parameters.
  • MacGyver
    MacGyver over 8 years
    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?
  • Chris Moschini
    Chris Moschini about 8 years
    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: i.imgur.com/tql3pUA.png superuser.com/a/315709/101698
  • ZX9
    ZX9 over 7 years
    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.
  • brz
    brz almost 7 years
    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.