编写自我更新Windows服务的最佳实践

时间:2009-10-22 15:55:47

标签: windows-services service auto-update

我们需要创建一个能够自我更新的Windows服务。

我想到了三个选择,

  1. 管理第一项服务的检索,卸载和安装的第二项服务。

  2. 使用某些第三方框架(建议欢迎。我相信.NET支持自动更新Windows窗体应用程序,但不支持Windows服务)

  3. 使用插件模型,其中服务只是一个包含更新和运行逻辑的shell,服务的业务逻辑包含在可以换出的DLL中。

  4. 任何人都能解释一下这个问题的解决方案吗?

    由于

3 个答案:

答案 0 :(得分:4)

我的一些想法。

1似乎有问题,因为你最终会处理你想要解决的情况,因为在某些时候更新程序需要更新。 3听起来不错但如果“换出”你的意思是在运行时使用一些花哨的反射加载dll我不确定性能是否会成为一个问题。

第四个选项是服务可以生成一个更新过程,允许它在运行之前根据需要更新更新可执行文件。从那里开始编写一个安装应用程序很简单,该服务将在关闭之前生成。

答案 1 :(得分:4)

Google有一个名为Omaha的开源框架,它完全可以完成您的观点1.的描述。它在其管理的应用程序外部,作为计划的Windows任务在后台运行。 Google使用Omaha来自动更新其Windows应用程序,包括Chrome。由于它来自Google,并且安装在每台运行Chrome的Windows计算机上,因此奥马哈功能非常强大。

有一个article online,它更详细地说明了如何使用Omaha来更新Windows服务。它辩称,由于Omaha具有异步特性,因此特别适合服务(相对于GUI应用程序)。

因此,您可以使用奥马哈来完成第2点和第1点的操作。恐怕我不知道你会怎么做3。

答案 2 :(得分:1)

我使用选项1.这些天更新程序进程很少更新。它使用一个XML文件,其中包含从哪里获取文件的详细信息(当前支持SVN,致力于添加NuGet支持)以及放置它们的位置。它还指定哪些是服务,哪些是网站,并指定用于每个项目的服务的名称。

进程轮询源,如果有新版本可用,则将其复制到新版本编号目录,然后更新服务。它还保留每个更新的5个副本,以便在出现问题时轻松回滚。

这是更新程序的核心代码,它停止现有服务,复制文件,然后重新启动它。

if (isService)
{
    log.Debug("Stopping service " + project.ServiceName);

    var service = GetService(project);
    if (service != null && 
        service.Status != System.ServiceProcess.ServiceControllerStatus.Stopped && service.Status != System.ServiceProcess.ServiceControllerStatus.StopPending)
    {
        service.Stop();
    }

    service.WaitForStatus(System.ServiceProcess.ServiceControllerStatus.Stopped, new TimeSpan(0, 1, 0));
    if (service.Status == System.ServiceProcess.ServiceControllerStatus.Stopped)
        log.Debug("Service stopped");
    else
        log.Error("ERROR: Expected Stopped by Service is " + service.Status);

}

log.Debug("Copying files over");
CopyFolder(checkoutDirectory, destinationDirectory);

if (isService)
{
    log.Debug("Starting service");
    var service = GetService(project);

    // Currently it doesn't create services, you need to do that manually
    if (service != null)
    {
        service.Start();

        service.WaitForStatus(System.ServiceProcess.ServiceControllerStatus.Running, new TimeSpan(0, 1, 0));

        if (service.Status == System.ServiceProcess.ServiceControllerStatus.Running)
            log.Debug("Service running");
        else
            log.Error("Service " + service.Status);
    }
}