如何调试Windows Service中的OnStop方法
Windows服务OnStop方法无法调试的解决办法
问题说明
编写了一个Windows Service,OnStart方法中的任务调度器注册逻辑可正常运行且能调试,但OnStop方法无法调试——在Visual Studio中点击停止按钮时,程序直接终止,不会进入OnStop代码段。相关代码如下:
Service1.cs核心代码
protected override void OnStart(string[] args) { // System.Diagnostics.Debugger.Launch(); try { // 此处代码可正常调试 } catch (Exception ie) { StreamWriter sw; sw = File.AppendText("D:\\DvrService.txt"); sw.WriteLine(ie.Message); sw.Close(); } } protected override void OnStop() { try { System.Diagnostics.Debugger.Launch(); foreach (string key in System.Configuration.ConfigurationManager.AppSettings) { var chromeDriverProcesses = Process.GetProcesses().Where(pr => pr.ProcessName == key.ToUpper()); // 不带'.exe' foreach (var process in chromeDriverProcesses) { process.Kill(); StreamWriter sw; sw = File.AppendText("E:\\DvrService.txt"); sw.WriteLine("Trying to kill Service" + key); sw.Close(); } } } catch (Exception ex) { //TODO: 记录错误 StreamWriter sw; sw = File.AppendText("E:\\DvrService.txt"); sw.WriteLine("Trying to kill Service"); sw.Close(); } }
Program.cs代码
static void Main() { #if DEBUG Service1 myService = new Service1(); myService.onDebug(); System.Threading.Thread.Sleep(System.Threading.Timeout.Infinite); #else ServiceBase[] ServicesToRun; ServicesToRun = new ServiceBase[] { new Service1() }; ServiceBase.Run(ServicesToRun); #endif }
问题原因
当前Debug模式的代码逻辑是直接实例化Service1、调用自定义的onDebug方法后用Thread.Sleep挂起进程,这种方式没有通过ServiceBase.Run来托管服务。Windows服务的生命周期(包括OnStop的触发)由服务控制管理器(SCM)通过ServiceBase托管层管理,直接挂起进程时,Visual Studio点击停止按钮会直接终止进程,不会触发服务的OnStop生命周期方法。
解决办法
方法一:通过服务控制管理器启停服务并附加调试器
- 安装服务:编译项目后,使用对应.NET版本的
InstallUtil.exe工具安装服务(示例路径:C:\Windows\Microsoft.NET\Framework\v4.0.30319\InstallUtil.exe),执行命令:InstallUtil.exe 你的服务程序.exe - 启动服务:打开
services.msc找到目标服务并启动。 - 附加调试器:在Visual Studio中点击菜单「调试」→「附加到进程」,找到服务对应的进程并附加。
- 触发OnStop:回到
services.msc停止服务,此时调试器会命中OnStop内的断点或Debugger.Launch(),即可正常调试。
方法二:修改Debug模式代码,模拟服务托管环境
修改Program.cs的Debug分支,用ServiceBase.Run托管服务,同时等待用户输入手动触发Stop,这样在Debug模式下可直接触发OnStop并调试:
static void Main() { #if DEBUG Service1 myService = new Service1(); // 用线程启动服务托管,避免阻塞主线程 var serviceThread = new Thread(() => ServiceBase.Run(new ServiceBase[] { myService })); serviceThread.IsBackground = true; serviceThread.Start(); Console.WriteLine("服务已启动,按任意键停止服务..."); Console.ReadKey(); // 手动调用Stop触发OnStop myService.Stop(); serviceThread.Join(); #else ServiceBase[] ServicesToRun; ServicesToRun = new ServiceBase[] { new Service1() }; ServiceBase.Run(ServicesToRun); #endif }
修改后,Debug模式运行会弹出控制台窗口,启动服务后按任意键即可触发OnStop方法,正常进行调试。
内容的提问来源于stack exchange,提问作者A.Goutam
相关产品推荐
相关产品推荐

