C#启动、停止Windows服务
Windows服务是Windows操作系统中一种在后台长时间运行的可执行程序,它们没有用户界面,通常在系统启动时自动运行,并在后台执行特定的任务。在开发和运维过程中,有时需要通过代码动态控制Windows服务的启动与停止。C#作为.NET平台的主流语言,提供了非常便捷的方式来管理Windows服务。本文将详细介绍如何使用C#启动和停止Windows服务,并给出完整的代码示例。
使用ServiceController类
.NET Framework和.NET Core/5+中,System.ServiceProcess.ServiceController 类提供了与Windows服务交互的核心功能。通过这个类,可以轻松获取服务状态、启动服务、停止服务、暂停服务以及继续服务。
要使用 ServiceController,首先需要在项目中引用 System.ServiceProcess 命名空间。在.NET Core/5+项目中,需要先安装 System.ServiceProcess.ServiceController NuGet包。
引入命名空间
using System.ServiceProcess;
检查服务状态
在启动或停止服务之前,通常需要先检查服务的当前状态,以避免执行无效操作。例如,如果服务已经启动,再次启动会抛出异常。以下代码展示了如何获取服务状态:
public ServiceControllerStatus GetServiceStatus(string serviceName)
{
using (ServiceController sc = new ServiceController(serviceName))
{
return sc.Status;
}
}ServiceControllerStatus 枚举包含以下常用值:Running、Stopped、Paused、StartPending、StopPending 等。
启动服务
启动服务需要调用 ServiceController.Start() 方法。在调用前,建议先检查服务是否已处于运行状态。由于服务启动可能需要一些时间,可以配合 WaitForStatus 方法等待服务达到指定状态。
public void StartService(string serviceName)
{
using (ServiceController sc = new ServiceController(serviceName))
{
if (sc.Status != ServiceControllerStatus.Running &&
sc.Status != ServiceControllerStatus.StartPending)
{
sc.Start();
// 等待服务达到 Running 状态,超时时间30秒
sc.WaitForStatus(ServiceControllerStatus.Running, TimeSpan.FromSeconds(30));
Console.WriteLine($"服务 {serviceName} 已成功启动。");
}
else
{
Console.WriteLine($"服务 {serviceName} 已经处于运行状态。");
}
}
}注意事项:如果启动服务时发生异常(如服务名称不存在、权限不足),Start 方法会抛出 System.ServiceProcess.ServiceController 相关的异常,建议使用 try-catch 进行捕获。
停止服务
停止服务的流程与启动类似,调用 ServiceController.Stop() 方法。同样建议先检查服务状态,并等待服务完全停止。
public void StopService(string serviceName)
{
using (ServiceController sc = new ServiceController(serviceName))
{
if (sc.Status == ServiceControllerStatus.Running ||
sc.Status == ServiceControllerStatus.StartPending)
{
sc.Stop();
// 等待服务达到 Stopped 状态,超时时间30秒
sc.WaitForStatus(ServiceControllerStatus.Stopped, TimeSpan.FromSeconds(30));
Console.WriteLine($"服务 {serviceName} 已成功停止。");
}
else
{
Console.WriteLine($"服务 {serviceName} 当前未运行,无需停止。");
}
}
}处理依赖服务
某些Windows服务可能依赖于其他服务。如果停止一个服务,其依赖的服务也会受到影响。ServiceController 类提供了 DependentServices 和 ServicesDependedOn 属性来获取依赖关系。在实际应用场景中,停止服务之前可能需要先停止依赖于它的服务。
public void StopServiceWithDependents(string serviceName)
{
using (ServiceController sc = new ServiceController(serviceName))
{
// 获取依赖于此服务的所有服务
ServiceController[] dependentServices = sc.DependentServices;
foreach (ServiceController dependent in dependentServices)
{
if (dependent.Status == ServiceControllerStatus.Running)
{
Console.WriteLine($"正在停止依赖服务: {dependent.ServiceName}");
dependent.Stop();
dependent.WaitForStatus(ServiceControllerStatus.Stopped, TimeSpan.FromSeconds(30));
}
}
// 停止目标服务
sc.Stop();
sc.WaitForStatus(ServiceControllerStatus.Stopped, TimeSpan.FromSeconds(30));
Console.WriteLine($"服务 {serviceName} 及其依赖服务已停止。");
}
}完整示例:启动与停止的封装类
下面给出一个完整的工具类,封装了启动、停止和检查服务状态的功能,并包含异常处理:
using System;
using System.ServiceProcess;
public class WindowsServiceManager
{
/// <summary>
/// 获取服务状态
/// </summary>
public ServiceControllerStatus GetStatus(string serviceName)
{
using (ServiceController sc = new ServiceController(serviceName))
{
return sc.Status;
}
}
/// <summary>
/// 启动服务,并等待其进入运行状态
/// </summary>
public void Start(string serviceName)
{
try
{
using (ServiceController sc = new ServiceController(serviceName))
{
if (sc.Status == ServiceControllerStatus.Running)
{
Console.WriteLine($"服务 [{serviceName}] 已经在运行。");
return;
}
if (sc.Status == ServiceControllerStatus.StartPending)
{
Console.WriteLine($"服务 [{serviceName}] 正在启动中,请稍后...");
sc.WaitForStatus(ServiceControllerStatus.Running, TimeSpan.FromSeconds(60));
return;
}
Console.WriteLine($"正在启动服务 [{serviceName}]...");
sc.Start();
sc.WaitForStatus(ServiceControllerStatus.Running, TimeSpan.FromSeconds(60));
Console.WriteLine($"服务 [{serviceName}] 启动成功。");
}
}
catch (Exception ex)
{
Console.WriteLine($"启动服务 [{serviceName}] 时发生错误: {ex.Message}");
throw;
}
}
/// <summary>
/// 停止服务,并等待其进入停止状态
/// </summary>
public void Stop(string serviceName)
{
try
{
using (ServiceController sc = new ServiceController(serviceName))
{
if (sc.Status == ServiceControllerStatus.Stopped)
{
Console.WriteLine($"服务 [{serviceName}] 已经处于停止状态。");
return;
}
if (sc.Status == ServiceControllerStatus.StopPending)
{
Console.WriteLine($"服务 [{serviceName}] 正在停止中,请稍后...");
sc.WaitForStatus(ServiceControllerStatus.Stopped, TimeSpan.FromSeconds(60));
return;
}
Console.WriteLine($"正在停止服务 [{serviceName}]...");
sc.Stop();
sc.WaitForStatus(ServiceControllerStatus.Stopped, TimeSpan.FromSeconds(60));
Console.WriteLine($"服务 [{serviceName}] 已停止。");
}
}
catch (Exception ex)
{
Console.WriteLine($"停止服务 [{serviceName}] 时发生错误: {ex.Message}");
throw;
}
}
/// <summary>
/// 重启服务
/// </summary>
public void Restart(string serviceName)
{
Stop(serviceName);
Start(serviceName);
Console.WriteLine($"服务 [{serviceName}] 已重启。");
}
}使用示例
以下代码演示了如何使用上述工具类来控制一个名为 Spooler(打印服务)的服务:
class Program
{
static void Main()
{
WindowsServiceManager manager = new WindowsServiceManager();
string serviceName = "Spooler";
// 检查状态
ServiceControllerStatus status = manager.GetStatus(serviceName);
Console.WriteLine($"服务 [{serviceName}] 当前状态: {status}");
// 停止服务
manager.Stop(serviceName);
// 启动服务
manager.Start(serviceName);
// 重启服务
manager.Restart(serviceName);
}
}注意:运行上述代码需要管理员权限,因为启动和停止Windows服务通常涉及系统级操作。如果在非管理员权限下运行,会抛出 System.ComponentModel.Win32Exception 异常,提示“访问被拒绝”。
安全与权限说明
控制Windows服务需要相应的权限。通常情况下:
启动和停止服务需要 管理员权限。
如果服务被配置为仅允许特定用户或组控制,即使拥有管理员权限也可能被拒绝。
建议在应用程序清单中声明
requireAdministrator执行级别,或使用进程提权的方式运行。
在开发和测试环境中,可以通过“以管理员身份运行”Visual Studio或编译后的exe来获得足够权限。在生产环境中,建议使用具有适当权限的专用服务账户来执行这些操作。
常见问题与解决方案
| 问题 | 可能原因 | 解决方案 |
|---|---|---|
| “访问被拒绝”异常 | 当前进程没有管理员权限 | 以管理员身份运行程序 |
| “服务名称无效”异常 | 服务名称拼写错误或服务未安装 | 检查服务名称(区分大小写),使用 sc query 命令列出所有服务 |
| 超时异常 | 服务启动/停止时间过长 | 增加 WaitForStatus 的超时时间,或异步等待 |
| 无法停止依赖服务 | 未处理依赖服务链 | 使用 DependentServices 属性递归停止 |
异步操作建议
如果需要在UI线程中控制服务(例如在WinForms或WPF应用中),建议使用异步方式调用,避免阻塞界面。可以使用 async / await 或 Task.Run 来执行服务操作。不过需要注意的是,ServiceController 本身没有提供异步方法,但可以借助 Task 实现异步等待。
using System.Threading.Tasks;
public async Task StartServiceAsync(string serviceName)
{
await Task.Run(() =>
{
using (ServiceController sc = new ServiceController(serviceName))
{
sc.Start();
sc.WaitForStatus(ServiceControllerStatus.Running, TimeSpan.FromSeconds(60));
}
});
}总结
使用C#的 ServiceController 类可以轻松地启动、停止和管理Windows服务。开发者只需要注意权限问题、服务名称的正确性以及依赖服务的处理,即可在应用程序中集成服务控制功能。本文提供的方法和代码示例可以直接用于实际项目,帮助开发者快速实现Windows服务的程序化管理。
无论你是开发系统管理工具、自动化部署脚本,还是构建监控平台,掌握这些基础操作都会让工作更加高效。