Best way to stop / start a service and wait for it to complete

Gerald Oakham 41 Reputation points
2022-10-05T14:44:44.007+00:00

Hi,
I am trying to stop a service, change the associated applications config file, start the service again, perform a task, and then reverse the process.
The problem I believe I am having is that the service itself, sometimes, can take a while to stop (other times it's lightning-fast).

The issue seems to arise when I try and reverse the config file change (the file config part is fine, it's the Stop/start of the server that seems to take longer than excepted ).

I was wondering if someone could advise me on the best way to stop and wait fully for a service to terminate before I can then continue.

So far, I have
ServiceController appDriver = new ServiceController("ServiceName");
private void Form1_Load(object sender, EventArgs eg)
{
try
{
string Status =appDriver.Status.ToString();

                    if (appStatus == "Running")  
                    {  
                        appDriver.Stop();  
                        appDriver.WaitForStatus(ServiceControllerStatus.Stopped);  
  
                        while (appStatus != "Stopped")  
                        {  
                            appDriver.Refresh();  
                            appStatus = OLDDriver.Status.ToString();  
                        }  
                    }  
< make a change to config file >  
  
                    appStatus = appDriver.Status.ToString();  
                    if (appStatus == "Stopped")  
                    {  
                        appDriver.Start();  
  
                         while (appStatus != "Running")  
                        {  
                            appDriver.Refresh();  
                           appStatus = appDriver.Status.ToString();  
                        }  
                    }  
< above code snippet works fine >  
  
< do some more things while the application is using the new config file >  
  
/// tried this as the previous coded hung app as the service took too long to stop, but getting same issue again  
                    Process cmdlne = new Process();  
                    cmdlne.StartInfo.FileName = "cmd.exe";  
                    cmdlne.StartInfo.CreateNoWindow = true;  
                    cmdlne.StartInfo.RedirectStandardInput = true;  
                    cmdlne.StartInfo.RedirectStandardOutput = true;  
                    cmdlne.StartInfo.UseShellExecute = false;  
                    cmdlne.Start();  
                    cmdlne.StandardInput.WriteLine("net stop ServiceName");  
                    cmdlne.StandardInput.Flush();  
                    cmdlne.StandardInput.Close();  
                    cmdlne.WaitForExit();  
  
< revert change to config file >  
  
appDStatus = appDriver.Status.ToString();  
  
                    if (appStatus == "Stopped")  
                    {  
                        appDriver.Start();  
  
                        while (appStatus != "Running")  
                        {  
                            appDriver.Refresh();  
                            appStatus = appDriver.Status.ToString();  
                        }  
                    }  
< carry on with other code >   
}  

The service can take up to 60 seconds to terminate, and although I think my code should be waiting nicely for this to happen, it doesn't seem to be.

Thank you

C#
C#
An object-oriented and type-safe programming language that has its roots in the C family of languages and includes support for component-oriented programming.
10,245 questions
0 comments No comments
{count} votes

2 answers

Sort by: Most helpful
  1. Michael Taylor 48,206 Reputation points
    2022-10-05T18:38:59.72+00:00

    Firstly you shouldn't be converting an enum to a string. That is wasteful and doesn't help anything.

       if (appDriver.Status == ServiceControllerStatus.Running)  
       {  
          appDriver.Stop();  
          appDriver.WaitForStatus(ServiceControllerStatus.Stopped);  
       };  
    

    Now let's fix the issues with your code. The first problem is your while loop is redundant and you can remove it. But this is ultimately where the problem is. It checks appStatus to see if it is stopped. Since that was a cached string version of the service status it will be Running the first time through. You refresh the service status and then query for the status of some service called OldDriver. So at this point you're not even looking at the correct service anymore. I believe this is why your code is not working correctly. But you don't need that while loop so remove it all and I think your code will behave correctly.

    For starting the service the same code works just by changing the status values being used.


  2. Gerald Oakham 41 Reputation points
    2022-10-07T08:50:00.263+00:00

    Hi, I went down a similar route yesterday as well and have been testing it yesterday (seemed to be ok atm )

            public void StopWindowsService(string serviceName, string errorlog)  
            {  
                try  
                {  
                    ServiceController serviceController = new ServiceController(serviceName);  
                    TimeSpan timeout = TimeSpan.FromMilliseconds(30000);  
                    serviceController.Stop();  
                    serviceController.WaitForStatus(ServiceControllerStatus.Stopped, timeout);  
                    System.IO.File.AppendAllText(errorlog, DateTime.Now.ToString() + " - (i) - " + serviceName + " Stopped." + Environment.NewLine);  
                }  
                catch (Exception _stopex)  
                {  
                    System.IO.File.AppendAllText(errorlog, DateTime.Now.ToString() + " - (w) - " + _stopex.Message + Environment.NewLine);  
                }  
            }  
      
      
      
            public void StartWindowsService(string serviceName, string errorlog)  
            {  
                try  
                {  
                    ServiceController serviceController = new ServiceController(serviceName);  
                    TimeSpan timeout = TimeSpan.FromMilliseconds(30000);  
                    serviceController.Start();  
                    serviceController.WaitForStatus(ServiceControllerStatus.Running, timeout);  
                    System.IO.File.AppendAllText(errorlog, DateTime.Now.ToString() + " - (i) - " +serviceName + " Started."  + Environment.NewLine);  
                }  
                catch (Exception _startex)  
                {  
                    System.IO.File.AppendAllText(errorlog, DateTime.Now.ToString() + " - (w) - "+ _startex.Message + Environment.NewLine);  
                }  
            }  
    

    Thank you again for your help