C#服务程序开发


引言

Windows服务(Windows Service)是在Windows操作系统后台运行的长期进程,无需用户交互即可执行特定功能。使用C#开发Windows服务程序是许多企业级应用和系统工具的基础。本文将全面介绍如何使用C#开发、安装和管理Windows服务程序。

1. Windows服务基础

1.1 服务程序特点

  • 在系统后台自动运行
  • 不依赖用户登录状态
  • 可以设置为随系统启动而自动运行
  • 通过服务控制管理器(SCM)管理

1.2 常见应用场景

  • 定时任务执行
  • 系统监控
  • 数据处理服务
  • 网络服务
  • 消息队列处理

2. 创建Windows服务项目

2.1 使用Visual Studio创建服务项目

  1. 新建项目 → Windows服务(.NET Framework)
  2. 项目会自动生成继承自ServiceBase的类
using System.ServiceProcess;

public partial class MyService : ServiceBase
{
    public MyService()
    {
        InitializeComponent();
    }

    protected override void OnStart(string[] args)
    {
        // 服务启动逻辑
    }

    protected override void OnStop()
    {
        // 服务停止逻辑
    }
}

2.2 .NET Core/5+中的服务开发

对于跨平台需求,可以使用Worker Service模板:

dotnet new worker -n MyBackgroundService

或使用Microsoft.Extensions.Hosting:

using Microsoft.Extensions.Hosting;

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .UseWindowsService() // 添加Windows服务支持
            .ConfigureServices((hostContext, services) =>
            {
                services.AddHostedService<Worker>();
            });
}

3. 服务核心开发

3.1 主要生命周期方法

protected override void OnStart(string[] args)
{
    // 启动服务时执行
    // 通常在此初始化资源、启动线程或定时器
}

protected override void OnStop()
{
    // 停止服务时执行
    // 释放资源、保存状态等
}

protected override void OnPause()
{
    // 服务暂停时执行(可选)
}

protected override void OnContinue()
{
    // 服务继续时执行(可选)
}

protected override void OnShutdown()
{
    // 系统关闭时执行(可选)
}

3.2 添加服务功能

定时任务实现

private Timer _timer;

protected override void OnStart(string[] args)
{
    _timer = new Timer(DoWork, null, TimeSpan.Zero, 
                      TimeSpan.FromMinutes(30));
}

private void DoWork(object state)
{
    // 定期执行的任务逻辑
    EventLog.WriteEntry("服务执行了定期任务", EventLogEntryType.Information);
}

protected override void OnStop()
{
    _timer?.Dispose();
}

事件日志记录

// 在构造函数中初始化事件日志
public MyService()
{
    InitializeComponent();

    if (!EventLog.SourceExists("MyServiceSource"))
    {
        EventLog.CreateEventSource("MyServiceSource", "MyServiceLog");
    }

    EventLog.Source = "MyServiceSource";
    EventLog.Log = "MyServiceLog";
}

// 记录信息
EventLog.WriteEntry("服务启动成功", EventLogEntryType.Information);

4. 服务安装与部署

4.1 添加安装程序

  1. 在设计视图右键点击 → 添加安装程序
  2. 会自动生成ProjectInstaller类和两个组件:
  • serviceProcessInstaller1 – 设置运行账户
  • serviceInstaller1 – 设置服务属性
[RunInstaller(true)]
public partial class ProjectInstaller : Installer
{
    public ProjectInstaller()
    {
        InitializeComponent();

        // 设置服务运行账户
        serviceProcessInstaller1.Account = ServiceAccount.LocalSystem;

        // 设置服务属性
        serviceInstaller1.ServiceName = "MyService";
        serviceInstaller1.DisplayName = "我的自定义服务";
        serviceInstaller1.Description = "这是一个示例Windows服务";
        serviceInstaller1.StartType = ServiceStartMode.Automatic;
    }
}

4.2 安装和卸载服务

使用InstallUtil.exe安装

# 安装
InstallUtil.exe MyService.exe

# 卸载
InstallUtil.exe /u MyService.exe

使用SC命令安装

sc create MyService binPath= "C:\path\to\MyService.exe" start= auto
sc description MyService "我的自定义服务"
sc start MyService

# 卸载
sc delete MyService

以编程方式安装

using System.Configuration.Install;
using System.ServiceProcess;

public static void InstallService(string exePath)
{
    ManagedInstallerClass.InstallHelper(new[] { exePath });
}

public static void UninstallService(string exePath)
{
    ManagedInstallerClass.InstallHelper(new[] { "/u", exePath });
}

5. 服务调试技巧

5.1 调试模式运行

修改Program.cs以支持调试模式:

static class Program
{
    static void Main()
    {
        if (Environment.UserInteractive)
        {
            // 调试模式运行
            var service = new MyService();
            service.OnDebugStart();
            Console.WriteLine("服务在调试模式下运行,按任意键停止...");
            Console.ReadKey();
            service.OnDebugStop();
        }
        else
        {
            // 正常服务模式运行
            ServiceBase[] ServicesToRun;
            ServicesToRun = new ServiceBase[] { new MyService() };
            ServiceBase.Run(ServicesToRun);
        }
    }
}

// 在服务类中添加调试方法
public partial class MyService : ServiceBase
{
    public void OnDebugStart()
    {
        OnStart(null);
    }

    public void OnDebugStop()
    {
        OnStop();
    }
}

5.2 附加到进程调试

  1. 安装并启动服务
  2. Visual Studio → 调试 → 附加到进程
  3. 选择服务进程(通常与项目同名)
  4. 设置断点进行调试

6. 高级主题

6.1 服务恢复选项

配置服务崩溃后自动重启:

// 在ProjectInstaller中
serviceInstaller1.ServicesDependedOn = new[] { "SomeDependentService" };

// 通过SC命令设置恢复选项
sc failure MyService reset= 60 actions= restart/60000/restart/60000/run/1000

6.2 多服务应用程序

static class Program
{
    static void Main()
    {
        ServiceBase[] ServicesToRun = new ServiceBase[]
        {
            new Service1(),
            new Service2(),
            new Service3()
        };
        ServiceBase.Run(ServicesToRun);
    }
}

6.3 与WCF集成

创建WCF服务宿主:

protected override void OnStart(string[] args)
{
    _serviceHost = new ServiceHost(typeof(MyWcfService));
    _serviceHost.Open();
}

protected override void OnStop()
{
    _serviceHost?.Close();
}

7. 最佳实践

  1. 异常处理:服务中所有代码都应包含try-catch块,防止服务意外停止
  2. 资源管理:确保正确释放所有资源(文件句柄、网络连接等)
  3. 性能考虑:避免在服务中使用过多内存或CPU资源
  4. 日志记录:实现详细的日志记录,便于故障排查
  5. 配置管理:使用配置文件(app.config)存储服务参数
  6. 版本控制:实现服务版本检查机制

结语

C# Windows服务开发是构建可靠后台应用程序的强大工具。通过合理设计服务架构、实现完善的错误处理和日志记录,可以创建出稳定高效的系统服务。对于现代开发,考虑使用Worker Service模式可以更好地支持跨平台场景。无论选择哪种方式,理解服务生命周期、掌握调试技巧和遵循最佳实践都是开发高质量服务程序的关键。


发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注