How to send a custom command to a .NET windows Ser

2019-01-13 02:34发布

问题:

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

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


回答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.