Windows服务失败的正确方法是什么?

J E*_*lis 40 c# windows-services

我继承了用C#编写的Windows服务.在极少数情况下,它会严重失败.但是,如何彻底失败并不清楚.Ross Bennett在bytes.com上优雅地陈述了这个问题.为了简单起见,我将在这里引用他.

啊,伙计们!

我一直在寻找这个,但我似乎无法从MSDN或谷歌中删除任何文档.我已经回顾了我在MSDN中开发Windows服务的每篇.NET文章.

我正在开发一个Windows服务应用程序.此服务从其他"管理器"应用程序存放的系统注册表(HKLM)中读取其配置数据.没有问题.

该服务使用工作线程来完成其工作.线程在OnStart()中创建,并在OnStop()中发信号/加入/处置.再次,没有问题.

在以下情况下,一切都很美妙:

  1. 系统管理员已正确设置所有内容,并且
  2. 外部网络资源都可以访问.

但当然,我们作为开发人员根本不能依赖:

  1. 系统管理员已正确设置所有内容,或
  2. 可以访问外部网络资源.

真的,我们需要的是服务应用程序有一些自己死亡的方式.如果网络资源出现故障,我们需要停止服务.但更重要的是,我们需要SCM知道它已经自行停止了.SCM需要知道该服务已经"失败"......并且还没有被某人关闭.

在"OnStart()"方法中调用"return"或抛出异常对于仍处于启动过程中的服务甚至没有帮助.SCM快速启动并且进程在任务管理器中继续运行 - 尽管它是实际上并没有做任何事情,因为从未创建和启动工作线程.

使用ServiceController实例也不会这样做.这似乎是SCM正常关机 - 而不是服务故障.因此,没有任何恢复操作或重启发生.(另外,MSDNful文档警告有关使用ServiceController使ServiceBtroller自身发生的ServiceBase后代的危险.)

我读过人们在PInvoking调用本机代码时只是为了在SCM中设置"Stopped"状态标志而搞乱的文章.但这并不会关闭服务运行的过程.

我真的很想知道以下方面:

  1. 从服务中关闭服务,在哪里
  2. SCM被适当地通知服务已经"停止",并且
  3. 该过程从任务管理器中消失.

涉及ServiceControllers的解决方案似乎不合适,只是因为2不满意.(框架文件特别禁止这样做,顺便提一下.)

我很欣赏任何建议,指向文档,甚至是有充分理由的推测.:-)哦!而且我很高兴能够接受我的错失.

最亲切的,

罗斯贝内特

Ste*_*end 33

本机代码中的最佳实践是使用非零退出代码调用SetServiceStatus以指示1)它已停止并且2)出错.

在托管代码中,您可以通过ServiceBase.ServiceHandle属性和P/Invoke-Win32 API 获取SCM句柄来实现相同的效果.

我不明白为什么SCM会对此进行不同的处理,而不是将ServiceBase.ExitCode属性设置为非零,然后ServiceBase.Stop实际调用.如果服务处于恐慌模式,P/Invoke可能更直接.

  • 我正在寻找的答案包含在这个答案中.简明的答案是:将ServiceBase.ExitCode属性设置为非零,然后调用ServiceBase.Stop. (20认同)
  • 试过这个(通过托管API和SetServiceStatus的PInvoke),如果配置这样做,这种方法不允许服务自动重启.它绝对停止了服务.调用`Environment.Exit()`或抛出异常而不捕获它会导致操作系统似乎正在寻找的"异常"终止,以便自动重启失败. (7认同)
  • @jglouie:请参阅http://serverfault.com/q/72318/206739,以解决您的问题。 (2认同)

Rya*_*ett 5

我发现Environment.Exit(1)对我来说很好.我通常把它放在一个捕获未处理的异常的方法中,并在我停止之前记录问题.它完全破坏了服务,但SCM也知道它已关闭.您可以将SCM设置为在服务次数下降x次时自动重新启动服务.我发现这比编写自己的重启/关闭代码更有用.