写了个简单的 Windows 服务程序

因为一些个人需求,想给家里的台式机加个开机通知的工具。一开始的解决方案是开机后自动执行 Python 脚本,然后发送邮件来通知,而现在看到了可以用 C# 写 Windows 服务程序来实现,于是折腾的劲就上来了。在这里记录下这两天写的小工具。

在写 Windows 服务时也是打算用邮件的方式去通知,但当时写着写着就想,也就通知个信息而已,至于用一个邮箱去给另一个邮箱发送邮件吗?这也太奇怪了,于是我就想像苹果那样可以通过系统推送服务给手机发送通知。

网上的 Apple 推送接口教程对我来说最难的一步是开发者账号和生成证书,后面我也大致看了下小米和华为的推送服务,最后我选用了 WxPusher (微信推送服务),不用 Server 酱是因为只能发送五条信息,不够用。

1. Push 方法调用后没收到通知

这是我第一个遇到的问题,至于为啥我会遇到这个问题纯属是我经验不够。

在断点调试后,我发现问题在 Json 字符串数据的拼接这块代码,我是直接将接收到的参数拼接在字符串里,此时拼接后是字符串了,但不是 Json 字符串,因为它的值没有被引号包括,导致没有成功发送请求。

1

为啥不用 Json 对象通过 Add 方法动态增加内容,再转为字符串?因为没必要多加一个库去处理,本来也就这点点文本。

2. 编译好的程序安装不了

根据逻辑写好代码,配置好安装程序后,根本安装不了服务,错误信息说的是 出现System.Security.SecurityException: 未找到源,但未能搜索某些或全部事件日志。不可访问的日志: Security。 网上的答案几乎都是说权限不够,但我确确实实是以管理员身份运行的 Bat,怎么可能没有权限啊。

后面我根据一些检索到的信息,发现是安装程序属性的 ServiceName 和服务程序 cs 文件属性的 ServiceName 不一致,而文档说的是要一致。

3. 在 OnStop 和 OnShutdown 事件里调用 Push 方法后没收到通知

测试时候,只有在 OnStart 事件里调用 Push 方法有发送通知外,其余两个事件根本没有完成 Push 方法里面的请求。通过断点调试查找问题时,发现每次发起请求后就没啥反应了,表现为执行到 await client.PostAsync 后就结束了,啥也没发生,通知也没收到。

对于这个问题我也不知道咋解决,于是我就用 ChatGPT 帮忙排查解决了,ChatGPT 说到:

使用异步方法需要注意:Push 方法被声明为异步方法,但在 OnStop 中直接调用异步方法可能会导致问题,因为在服务停止时可能无法等待异步操作完成。这可能会导致异步操作未能完成或引发异常。在 OnStop 中调用异步方法时,最好使用 .Wait() 或 .GetAwaiter().GetResult() 等方法来同步等待异步操作的完成。

我根据它的提示和代码,把 Push 方法 void 类型改为 async Task,在调用时加个 Wait() 方法就行了,修改后终于是成功收到通知了。

4. 家里的台式机在开机和关机时没有发送通知

在虚拟机测试时是可以用的,结果一放到台式机后就跟“失灵”了一样,没反应。

在台式机的服务管理器那手动启动和关闭服务都是正常发送通知的,但就是开机和关机过程没有发送通知。而且开机后,服务管理器里显示这个服务是有运行的,也就是说它没有调用到 Push 方法,这就奇怪了啊,虚拟机里是正常的。我还发现只有重启电脑时,才有收到通知。

后面检索到一篇文章说关闭快速启动就可以了,果然,已关闭这个设置后就正常了。