.NET Framework 封裝了 SCM (Service Control Manager) 互動細節,開發者只需繼承 ServiceBase 並實作生命週期事件。
System.ServiceProcess.dll, System.Configuration.Install.dllusing System.ServiceProcess;
using System.Threading;
public class MyService : ServiceBase {
private Thread _worker;
private volatile bool _running;
public MyService() {
ServiceName = "MyCustomService";
CanPauseAndContinue = true;
CanShutdown = true;
}
protected override void OnStart(string[] args) {
_running = true;
_worker = new Thread(DoWork) { IsBackground = true };
_worker.Start();
}
protected override void OnStop() {
_running = false;
_worker?.Join(3000); // 等待優雅退出,最多 3 秒
}
protected override void OnPause() => _running = false;
protected override void OnContinue() => _running = true;
private void DoWork() {
while (_running) {
// 實際業務邏輯:輪詢資料庫、監控目錄、處理佇列...
Thread.Sleep(1000);
}
}
}
關鍵規則:OnStart/OnStop/OnPause/OnContinue 必須在 30 秒內返回,否則 SCM 判定服務掛起並報錯。耗時操作務必放入背景執行緒。
static class Program {
static void Main() {
ServiceBase.Run(new MyService());
}
}
[RunInstaller(true)]
public class MyServiceInstaller : Installer {
public MyServiceInstaller() {
var processInstaller = new ServiceProcessInstaller {
Account = ServiceAccount.LocalSystem // 或 NetworkService/User
};
var serviceInstaller = new ServiceInstaller {
ServiceName = "MyCustomService",
DisplayName = "我的自訂服務",
Description = "示範 C# Windows Service 基本架構",
StartType = ServiceStartMode.Automatic
};
Installers.Add(processInstaller);
Installers.Add(serviceInstaller);
}
}
// 開啟 Developer Command Prompt for VS (管理員)
installutil.exe MyService.exe // 安裝
installutil.exe /u MyService.exe // 解除安裝
services.msc 中看到「我的自訂服務」服務無 UI,需另建 WinForms/WPF/Console 客戶端,透過以下方式互動:
ServiceController:啟動/停止/暫停/狀態查詢AppDomain.CurrentDomain.UnhandledException + 任務內 try-catch 記錄Mutex 防止手動雙擊 EXE 造成雙進程appsettings.json + IConfiguration,避免重新編譯OnStop 發送取消令牌,等待進行中任務完成 (設定逾時)NetworkService 別用 LocalSystem// Program.cs
IHost host = Host.CreateDefaultBuilder(args)
.UseWindowsService() // 自動偵測 SCM
.ConfigureServices((ctx, svc) => {
svc.AddHostedService();
})
.Build();
host.Run();
// Worker.cs
public class Worker : BackgroundService {
protected override async Task ExecuteAsync(CancellationToken stoppingToken) {
while (!stoppingToken.IsCancellationRequested) {
// Do work
await Task.Delay(1000, stoppingToken);
}
}
}
新版泛型主機內建 DI、設定、日誌、生命週期管理,強烈建議新專案直接用 .NET 6/8 LTS。