【问题标题】:How can I restart a windows service programmatically in .NET如何在 .NET 中以编程方式重新启动 Windows 服务
【发布时间】:2023-03-08 04:35:01
【问题描述】:

如何在 .NET 中以编程方式重新启动 Windows 服务?
另外,我需要在服务重启完成后进行操作。

【问题讨论】:

    标签: c# windows-services


    【解决方案1】:

    This article 使用ServiceController 类编写启动、停止和重新启动Windows 服务的方法;可能值得一看。

    文章摘录(“重启服务”方法):

    public static void RestartService(string serviceName, int timeoutMilliseconds)
    {
      ServiceController service = new ServiceController(serviceName);
      try
      {
        int millisec1 = Environment.TickCount;
        TimeSpan timeout = TimeSpan.FromMilliseconds(timeoutMilliseconds);
    
        service.Stop();
        service.WaitForStatus(ServiceControllerStatus.Stopped, timeout);
    
        // count the rest of the timeout
        int millisec2 = Environment.TickCount;
        timeout = TimeSpan.FromMilliseconds(timeoutMilliseconds - (millisec2-millisec1));
    
        service.Start();
        service.WaitForStatus(ServiceControllerStatus.Running, timeout);
      }
      catch
      {
        // ...
      }
    }
    

    【讨论】:

    • 该解决方案的问题在于,在我的情况下,此操作需要管理员权限。而且我无法在运行时更改(指定)用户。
    • @Slavik 如果需要管理员权限,那么您将以编程方式采用哪种方法并不重要;您甚至可能需要使用管理员级别的控制台来使用命令行工具,如果您通过任务管理器尝试,您可能会收到拒绝访问。
    【解决方案2】:

    看看ServiceController 类。

    要执行重启服务时需要做的操作,我猜你应该在Service中自己做(如果是你自己的服务)。
    如果您无权访问服务源,那么也许您可以使用ServiceControllerWaitForStatus 方法。

    【讨论】:

    • 这是否在服务本身内工作? Windows 服务能否以编程方式自行重启?
    【解决方案3】:

    ServiceController类使用示例

    private void RestartWindowsService(string serviceName)
    {
        ServiceController serviceController = new ServiceController(serviceName);
        try
        {
            if ((serviceController.Status.Equals(ServiceControllerStatus.Running)) || (serviceController.Status.Equals(ServiceControllerStatus.StartPending)))
            {
                serviceController.Stop();
            }
            serviceController.WaitForStatus(ServiceControllerStatus.Stopped);
            serviceController.Start();
            serviceController.WaitForStatus(ServiceControllerStatus.Running);
        }
        catch
        {
            ShowMsg(AppTexts.Information, AppTexts.SystematicError, MessageBox.Icon.WARNING);
        }
    }
    

    【讨论】:

      【解决方案4】:

      您也可以调用net 命令来执行此操作。示例:

      System.Diagnostics.Process.Start("net", "stop IISAdmin");
      System.Diagnostics.Process.Start("net", "start IISAdmin");
      

      【讨论】:

      • 我喜欢这个答案,因为它不需要额外的引用或辅助类。您可能想添加一个 .WaitForExit();在再次启动之前确保服务已停止:System.Diagnostics.Process.Start("net", "stop IISAdmin").WaitForExit();System.Diagnostics.Process.Start("net", "start IISAdmin").WaitForExit();
      【解决方案5】:

      此答案基于@Donut 答案(该问题投票最多的答案),但有一些修改。

      1. 在每次使用后处理ServiceController 类,因为它实现了IDisposable 接口。
      2. 减少方法的参数:不需要为每个方法传递serviceName参数,我们可以在构造函数中设置它,其他方法将使用该服务名称。
        这也更加 OOP 友好。
      3. 以此类可用作组件的方式处理 catch 异常。
      4. 从每个方法中删除timeoutMilliseconds 参数。
      5. 添加两个新方法StartOrRestartStopServiceIfRunning,可以将其视为其他基本方法的包装器,这些方法的目的只是为了避免异常,如注释中所述。

      这是课程

      public class WindowsServiceController
      {
          private string serviceName;
      
          public WindowsServiceController(string serviceName)
          {
              this.serviceName = serviceName;
          }
      
          // this method will throw an exception if the service is NOT in Running status.
          public void RestartService()
          {
              using (ServiceController service = new ServiceController(serviceName))
              {
                  try
                  {
                      service.Stop();
                      service.WaitForStatus(ServiceControllerStatus.Stopped);
      
                      service.Start();
                      service.WaitForStatus(ServiceControllerStatus.Running);
                  }
                  catch (Exception ex)
                  {
                      throw new Exception($"Can not restart the Windows Service {serviceName}", ex);
                  }
              }
          }
      
          // this method will throw an exception if the service is NOT in Running status.
          public void StopService()
          {
              using (ServiceController service = new ServiceController(serviceName))
              {
                  try
                  {
                      service.Stop();
                      service.WaitForStatus(ServiceControllerStatus.Stopped);
                  }
                  catch (Exception ex)
                  {
                      throw new Exception($"Can not Stop the Windows Service [{serviceName}]", ex);
                  }
              }
          }
      
          // this method will throw an exception if the service is NOT in Stopped status.
          public void StartService()
          {
              using (ServiceController service = new ServiceController(serviceName))
              {
                  try
                  {
                      service.Start();
                      service.WaitForStatus(ServiceControllerStatus.Running);
                  }
                  catch (Exception ex)
                  {
                      throw new Exception($"Can not Start the Windows Service [{serviceName}]", ex);
                  }
              }
          }
      
          // if service running then restart the service if the service is stopped then start it.
          // this method will not throw an exception.
          public void StartOrRestart()
          {
              if (IsRunningStatus)
                  RestartService();
              else if (IsStoppedStatus)
                  StartService();
          }
      
          // stop the service if it is running. if it is already stopped then do nothing.
          // this method will not throw an exception if the service is in Stopped status.
          public void StopServiceIfRunning()
          {
              using (ServiceController service = new ServiceController(serviceName))
              {
                  try
                  {
                      if (!IsRunningStatus)
                          return;
      
                      service.Stop();
                      service.WaitForStatus(ServiceControllerStatus.Stopped);
                  }
                  catch (Exception ex)
                  {
                      throw new Exception($"Can not Stop the Windows Service [{serviceName}]", ex);
                  }
              }
          }
      
          public bool IsRunningStatus => Status == ServiceControllerStatus.Running;
      
          public bool IsStoppedStatus => Status == ServiceControllerStatus.Stopped;
      
          public ServiceControllerStatus Status
          {
              get
              {
                  using (ServiceController service = new ServiceController(serviceName))
                  {
                      return service.Status;
                  }
              }
          }
      }
      

      【讨论】:

        【解决方案6】:

        怎么样

        var theController = new System.ServiceProcess.ServiceController("IISAdmin");
        
        theController.Stop();
        theController.Start();
        

        不要忘记将 System.ServiceProcess.dll 添加到您的项目中以使其正常工作。

        【讨论】:

          【解决方案7】:

          看到这个article

          这是来自article 的sn-p。

          //[QUICK CODE] FOR THE IMPATIENT
          using System;
          using System.Collections.Generic;
          using System.Text;
          // ADD "using System.ServiceProcess;" after you add the 
          // Reference to the System.ServiceProcess in the solution Explorer
          using System.ServiceProcess;
          namespace Using_ServiceController{
              class Program{
                  static void Main(string[] args){
                      ServiceController myService = new ServiceController();
                      myService.ServiceName = "ImapiService";
                      string svcStatus = myService.Status.ToString();
                          if (svcStatus == "Running"){
                              myService.Stop();
                          }else if(svcStatus == "Stopped"){
                              myService.Start();
                          }else{
                              myService.Stop();
                          }
                  }
              }
          }
          

          【讨论】:

          • 在枚举上调用 ToString() 然后比较字符串而不是枚举有什么意义?
          【解决方案8】:

          我需要更复杂的东西,因为有时无法重新启动具有依赖关系的服务而只是抛出异常或服务可以设置为“禁用”等等。

          这就是我所做的:

          (它检查服务是否存在,如果它“禁用”,它将设置服务为“自动”,当它无法重新启动服务时,它将使用 taskkill 命令通过 PID 杀死服务,然后重新启动它(你需要是小心依赖服务,因为你也需要启动/重新启动它们)。

          如果重启成功,它只会返回真/假

          仅在 WIN10 上测试。

          PS:正在开发使用 taskkill 时检测依赖服务并重新启动它们的版本

          //Get windows service status
              public static string GetServiceStatus(string NameOfService)
              {
                  ServiceController sc = new ServiceController(NameOfService);
          
                  switch (sc.Status)
                  {
                      case ServiceControllerStatus.Running:
                          return "Running";
                      case ServiceControllerStatus.Stopped:
                          return "Stopped";
                      case ServiceControllerStatus.Paused:
                          return "Paused";
                      case ServiceControllerStatus.StopPending:
                          return "Stopping";
                      case ServiceControllerStatus.StartPending:
                          return "Starting";
                      default:
                          return "Status Changing";
                  }
              }
          
              //finds if service exists in OS
              public static bool DoesServiceExist(string serviceName)
              {
                  return ServiceController.GetServices().Any(serviceController => serviceController.ServiceName.Equals(serviceName));
              }
          
              //finds startup type of service
              public static string GetStartupType(string serviceName)
              {
                  ManagementObject objManage = new ManagementObject("Win32_Service.Name='"+serviceName+"'");
                  objManage.Get();
          
                  string status1 = objManage["StartMode"].ToString();
          
                  return status1;
              }
          
              //restart service through PID
              public static bool RestartServiceByPID(string NameOfService)
              {
                  LogWriter log = new LogWriter("TaskKilling: " + NameOfService);
          
                  string strCmdText = "/C taskkill /f /fi \"SERVICES eq " + NameOfService + "\"";
                  Process.Start("CMD.exe", strCmdText);
          
                  using(ServiceController ScvController = new ServiceController(NameOfService))
                  {
                      ScvController.WaitForStatus(ServiceControllerStatus.Stopped);
          
                      if (GetServiceStatus(NameOfService) == "Stopped")
                      {
                          ScvController.Start();
                          ScvController.WaitForStatus(ServiceControllerStatus.Running);
          
                          if (GetServiceStatus(NameOfService) == "Running")
                          {
                              return true;
                          }
                          else
                          {
                              return false;
                          }
          
                      }
                      else
                      {
                          return false;
                      }
                  }
              }
          
              //Restart windows service
              public static bool RestartWindowsService(string NameOfService)
              {
          
                  try
                  {
                      //check if service exists
                      if(DoesServiceExist(NameOfService) == false)
                      {
                          MessageBox.Show("Service " + NameOfService + " was not found.");
                          return false;
                      }
                      else
                      {
                          //if it does it check startup type and if it is disabled it will set it to "Auto"
                          if (GetStartupType(NameOfService) == "Disabled")
                          {
                              using (var svc = new ServiceController(NameOfService))
                              {
                                  ServiceHelper.ChangeStartMode(svc, ServiceStartMode.Automatic);
          
                                  if (svc.Status != ServiceControllerStatus.Running)
                                  {
                                      svc.Start();
                                      svc.WaitForStatus(ServiceControllerStatus.Running);
          
                                      if(GetServiceStatus(NameOfService) == "Running")
                                      {
                                          return true;
                                      }
                                      else
                                      {
                                          return false;
                                      }
                                  }
                                  else
                                  {
                                      svc.Stop();
                                      svc.WaitForStatus(ServiceControllerStatus.Stopped);
          
                                      if(GetServiceStatus(NameOfService) == "Stopped")
                                      {
                                          svc.Start();
                                          svc.WaitForStatus(ServiceControllerStatus.Running);
          
                                          if(GetServiceStatus(NameOfService) == "Running")
                                          {
                                              return true;
                                          }
                                          else
                                          {
                                              return false;
                                          }
                                      }
                                      //restart through PID
                                      else
                                      {
                                          return RestartServiceByPID(NameOfService);
                                      }
                                  }
          
                              }
                          }
                          //If service is not disabled it will restart it
                          else
                          {
                              using(ServiceController ScvController = new ServiceController(NameOfService))
                              {
                                  if(GetServiceStatus(NameOfService) == "Running")
                                  {
          
                                      ScvController.Stop();
                                      ScvController.WaitForStatus(ServiceControllerStatus.Stopped);
          
                                      if(GetServiceStatus(NameOfService) == "Stopped")
                                      {
                                          ScvController.Start();
                                          ScvController.WaitForStatus(ServiceControllerStatus.Running);
          
                                          if(GetServiceStatus(NameOfService) == "Running")
                                          {
                                              return true;
                                          }
                                          else
                                          {
                                              return false;
                                          }
          
                                      }
                                      //if stopping service fails, it uses taskkill
                                      else
                                      {
                                          return RestartServiceByPID(NameOfService);
                                      }
                                  }
                                  else
                                  {
                                      ScvController.Start();
                                      ScvController.WaitForStatus(ServiceControllerStatus.Running);
          
                                      if(GetServiceStatus(NameOfService) == "Running")
                                      {
                                          return true;
                                      }
                                      else
                                      {
                                          return false;
                                      }
          
                                  }
                              }
                          }
                      }
                  }
                  catch(Exception ex)
                  {
                      return RestartServiceByPID(NameOfService);
                  }
              }
          

          【讨论】:

            【解决方案9】:

            您可以设置服务在失败后重新启动。所以可以通过抛出异常来强制重启。

            使用服务属性上的恢复选项卡。

            请务必使用重置失败计数属性来防止服务完全停止。

            【讨论】:

              【解决方案10】:

              使用大于 0 的错误代码调用 Environment.Exit,这似乎很合适,然后在安装时我们将服务配置为在出错时重新启动。

              Environment.Exit(1);
              

              我在我的服务中做了同样的事情。它工作正常。

              【讨论】:

              • 服务重启后的操作呢?
              • 表现正常,重新开始。
              猜你喜欢
              • 1970-01-01
              • 2010-09-18
              • 2011-10-03
              • 1970-01-01
              • 1970-01-01
              • 2016-07-11
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多