Controlling a Service






Controlling a Service

Problem

You need to programmatically manipulate a service that your application interacts with.

Solution

Use the System.ServiceProcess.ServiceController class to control the service. ServiceController allows you to interact with an existing service and to read and change its properties. In the example, it will be used to manipulate the ASP.NET State Service. The name, the service type, and the display name are easily available from the ServiceName, ServiceType, and DisplayName properties.

    ServiceController scStateService = new ServiceController("COM+ Event System");
    Console.WriteLine("Service Name: " + scStateService.ServiceName);
    Console.WriteLine("Service Type: " + scStateService.ServiceType.ToString( ));
    Console.WriteLine("Display Name: " + scStateService.DisplayName);

The ServiceType enumeration has a number of values, shown in Figure.

The ServiceType enumeration values

Value

Description

Adapter

Service that serves a hardware device

FileSystemDriver

Driver for the filesystem (kernel level)

InteractiveProcess

Service that communicates with the desktop

KernelDriver

Low-level hardware device driver

RecognizerDriver

Driver for identifying filesystems on startup

Win32OwnProcess

Win32 program that runs as a service in its own process

Win32ShareProcess

Win32 program that runs as a service in a shared process like SvcHost


One useful task is to determine a service's dependents. The services that depend on the current service are accessed through the DependentServices property, an array of ServiceController instances (one for each dependent service):

	foreach (ServiceController sc in scStateService.DependentServices)
	{
	    Console.WriteLine(scStateService.DisplayName + " is depended on by: " +
	                sc.DisplayName);
	}

To see the services that the current service does depend on, the ServicesDependedOn array contains ServiceController instances for each of those:

	foreach (ServiceController sc in scStateService.ServicesDependedOn)
	{
	    Console.WriteLine(scStateService.DisplayName + " depends on: " +
	                sc.DisplayName);
	}

One of the most important things about services is what state they are in. A service doesn't do much good if it is supposed to be running and it isn'tor worse yet, it is supposed to be disabled (perhaps as a security risk) and isn't. To find out the current status of the service, check the Status property. For this example, the original state of the service will be saved so it can be restored later in the originalState variable.

	Console.WriteLine("Status: " + scStateService.Status);
	// Save original state.
	ServiceControllerStatus originalState = scStateService.Status;

If a service is stopped, it can be started with the Start method. First, check if the service is stopped, then once Start has been called on the ServiceController instance, the WaitForStatus method should be called to make sure that the service started. WaitForStatus can take a timeout value so that the application is not waiting forever for the service to start in the case of a problem.

	// If it is stopped, start it.
	TimeSpan serviceTimeout = TimeSpan.FromSeconds(60);
	if (scStateService.Status == ServiceControllerStatus.Stopped)
	{
	    scStateService.Start();
	    // Wait up to 60 seconds for start.
	    scStateService.WaitForStatus(ServiceControllerStatus.Running, serviceTimeout);
	}
	Console.WriteLine("Status: " + scStateService.Status);

Services can also be paused. If the service is paused, the application needs to check if it can be continued by looking at the CanPauseAndContinue property. If so, the Continue method will get the service going again, and the WaitForStatus method should be called to wait until it does:

	// If it is paused, continue.
	if (scStateService.Status == ServiceControllerStatus.Paused)
	{
	    if(scStateService.CanPauseAndContinue)
	    {
	        scStateService.Continue();
	        // Wait up to 60 seconds for running.
	        scStateService.WaitForStatus(ServiceControllerStatus.Running,
	                            serviceTimeout);
	    }
	}
	Console.WriteLine("Status: " + scStateService.Status);

	// Should be running at this point.

Determining if a service can be stopped is done through the CanStop property. If it can be stopped, then stopping it is a matter of calling the Stop method followed by WaitForStatus:

	// Can we stop it?
	if (scStateService.CanStop)
	{
	    scStateService.Stop();
	    // Wait up to 60 seconds for stop.
	    scStateService.WaitForStatus(ServiceControllerStatus.Stopped, serviceTimeout);
	}
	Console.WriteLine("Status: " + scStateService.Status);

Now it is time to set the service back to how you found it. The originalState variable has the original state, and the switch statement holds actions for taking the service from the current stopped state to its original state:

	// Set it back to the original state.
	switch (originalState)
	{
	    case ServiceControllerStatus.Stopped:
	        if (scStateService.CanStop)
	        {
	            scStateService.Stop( );
	        }
	        break;
	    case ServiceControllerStatus.Running:
	        scStateService.Start( );
	        // Wait up to 60 seconds for stop.
	        scStateService.WaitForStatus(ServiceControllerStatus.Running,
	                        serviceTimeout);
	        break;
	    case ServiceControllerStatus.Paused:
	        // If it was paused and is stopped, need to restart so we can pause.
	        if (scStateService.Status == ServiceControllerStatus.Stopped)
	        {
	            scStateService.Start( );
	            // Wait up to 60 seconds for start.
	            scStateService.WaitForStatus(ServiceControllerStatus.Running,
	                            serviceTimeout);
	        }
	        // Now pause.
	        if (scStateService.CanPauseAndContinue)
	        {
	            scStateService.Pause( );
	            // Wait up to 60 seconds for stop.
	            scStateService.WaitForStatus(ServiceControllerStatus.Paused,
	                            serviceTimeout);
	    }
	        break;
	}

In order to be sure that the Status property is correct on the service, the application should call Refresh to update it before testing the value of the Status property. Once the application is done with the service, call the Close method.

	scStateService.Refresh();
	Console.WriteLine("Status: " + scStateService.Status.ToString());

	// Close it.
	scStateService.Close();

Discussion

Services run many of the operating system functions today. They usually run under a system account (LocalSystem, NetworkService, LocalService) or a specific user account that has been granted specific permissions and rights. If your application uses a service, then this is a good way to determine if everything for the service to run is set up and configured properly before your application attempts to use it. Not all applications depend on services directly. But if your application does, or you have written a service as part of your application, it can be handy to have an easy way to check the status of your service and possibly correct the situation.

See Also

See the "ServiceController Class" and "ServiceControllerStatus Enumeration" topics in the MSDN documentation.



 Python   SQL   Java   php   Perl 
 game development   web development   internet   *nix   graphics   hardware 
 telecommunications   C++ 
 Flash   Active Directory   Windows