引言

2015年第一篇,Winform在线更新,算是重操旧业吧,09年刚到北京时一直做硬件联动编程,所以大多数时间都在搞Winform, 但是从来没做过在线更新这个功能,前几天参与部门另一个项目,上来就需要加一个在线更新。 该自动更新组件核心是圣殿骑士开发的,另外参考逆水寒龙使用情况,当我拿到这个组件源代码时并不知道如何去用,花了大半天时间也没调试通过,所以把我遇到的问题和解决方法记录下来,方便后续其他Coder使用时查看使用方法。

在线更新思路

1、请求远程站点Version.xml 或者请求Web服务器都可以,最主要是对比服务器端配置文件版本号和本地配置文件版本号。

2、从远程站点下载文件。

3、覆盖本地可执行文件及用到的Dll,当然覆盖之前需要关掉本地exe进程或者windows服务进程。

4、文件覆盖后修改本地配置文件AutoUpdater.config.

5、覆盖后重新启动可执行程序或者windows服务。

该AutoUpdater缺点(使用过程中已完善)

1、没看到圣殿骑士如何使用该组件,参考逆水寒龙Demo时,找到了主程序关闭的地方。

2、在下载文件时没有考虑到远程服务器新增文件时处理本地AutoUpdater.config,也就是说更新程序处理时是基于本地配置文件config.UpdateFileList。

3、没有针对windows服务处理进程(已完善windows服务处理类)。

使用时遇到的问题

1、不知道如何使用该组件?

使用该组件时项目应该具备4部分:Web站点用于接受请求及下载需更新文件、AutoUpdater更新组件、MainApplication(也就是你的主程序)、UpdateApplication(更新程序入口,通过主程序启动,在这个程序内部调用AutoUpdater组件)。

2、 不知道合适去关闭主程序和windows服务

后在看逆水寒龙的Demo中看到他是在文件下载前,当你点击确认下载时关闭进程。

if (bDownload)
{
//关闭windows service
ServiceProcess serviceProcess = new ServiceProcess();
serviceProcess.StopService(); //关掉主程序
OperProcess oper=new OperProcess();
oper.InitUpdateEnvironment(); DownloadConfirm dc = new DownloadConfirm(downloadList);
if (this.OnShow != null)
this.OnShow(); if (DialogResult.OK == dc.ShowDialog())
{
StartDownload(downloadList);
}
}

3、文件下载后临时目录和源程序主目录口径不一致

这个根据自己需要调整文件Copy、Move代码。我们的程序可执行文件和主要Dll都是放在一个单独的文件里而不是默认的Bin\Debug下。所以我的做法就是把下载文件从TempFolder移动到可执行源文件根目录下。具体代码在DownloadProgress窗体的ProcDownload方法中处理。

if (!string.IsNullOrEmpty(tempFolderPath))
{
oldPath = Path.Combine(CommonUnitity.SystemBinUrl, file.FileName);
newPath = Path.Combine(CommonUnitity.SystemBinUrl + ConstFile.TEMPFOLDERNAME + tempUrlPath, file.FileName);
}

4、 文件下载移动复制后合适启动应用程序

在更新程序里添加finally代码,启动windows服务、启动主程序、关闭更新程序(UpdateApplication)。

void InitAndCheck()
{
bool bHasError = false;
IAutoUpdater autoUpdater = new AutoUpdater(); try
{
autoUpdater.Update();
}
catch (WebException exp)
{
MessageBox.Show("Can not find the specified resource");
bHasError = true;
}
catch (XmlException exp)
{
bHasError = true;
MessageBox.Show("Download the upgrade file error");
}
catch (NotSupportedException exp)
{
bHasError = true;
MessageBox.Show("Upgrade address configuration error");
}
catch (ArgumentException exp)
{
bHasError = true;
MessageBox.Show("Download the upgrade file error");
}
catch (Exception exp)
{
bHasError = true;
MessageBox.Show("An error occurred during the upgrade process");
}
finally
{
if (bHasError == true)
{
try
{
autoUpdater.RollBack();
}
catch (Exception)
{ }
}
ServiceProcess serviceProcess = new ServiceProcess();
serviceProcess.StartService(); OperProcess oper = new OperProcess();
oper.StartProcess();
}
}

5、 当Web站点出现新增文件时没有同步到本地配置文件。

看源代码是发现修改本地AutoUpdater.config是基于本地UpdateFileList,只需要把Web端新增文件信息添加到该List中,序列化本地config时就会同步。

LocalFile tempFile = null;
foreach (RemoteFile file in listRemotFile.Values)
{
downloadList.Add(new DownloadFileInfo(file.Url, file.Path, file.LastVer, file.Size)); //把远程服务器新增文件加入config.UpdateFileList, 修改本地AutoUpdater.config时使用。
tempFile = new LocalFile(file.Path, file.LastVer, file.Size);
config.UpdateFileList.Add(tempFile); if (file.NeedRestart)
bNeedRestart = true;
}

6、添加windows服务处理类

public class ServiceProcess
{
#region 判断window服务是否启动
/// <summary>
/// 判断某个Windows服务是否启动
/// </summary>
/// <returns></returns>
private bool IsServiceStart(string serviceName)
{
ServiceController psc = new ServiceController(serviceName);
bool bStartStatus = false;
try
{
if (!psc.Status.Equals(ServiceControllerStatus.Stopped))
{
bStartStatus = true;
} return bStartStatus;
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}
#endregion #region 启动服务
private bool StartService(string serviceName)
{
bool flag = true;
if (ServiceIsExisted(serviceName))
{
System.ServiceProcess.ServiceController service = new System.ServiceProcess.ServiceController(serviceName);
if (service.Status != System.ServiceProcess.ServiceControllerStatus.Running && service.Status != System.ServiceProcess.ServiceControllerStatus.StartPending)
{
service.Start();
for (int i = 0; i < 60; i++)
{
service.Refresh();
System.Threading.Thread.Sleep(1000);
if (service.Status == System.ServiceProcess.ServiceControllerStatus.Running)
{
break;
}
if (i == 59)
{
flag = false;
}
}
}
}
return flag;
}
#endregion #region 停止服务
private bool StopService(string serviceName)
{
bool flag = true;
if (ServiceIsExisted(serviceName))
{
System.ServiceProcess.ServiceController service = new System.ServiceProcess.ServiceController(serviceName);
if (service.Status == System.ServiceProcess.ServiceControllerStatus.Running)
{
service.Stop();
for (int i = 0; i < 60; i++)
{
service.Refresh();
System.Threading.Thread.Sleep(1000);
if (service.Status == System.ServiceProcess.ServiceControllerStatus.Stopped)
{
break;
}
if (i == 59)
{
flag = false;
}
}
}
}
return flag;
}
#endregion #region 判断window服务是否存在
private bool ServiceIsExisted(string serviceName)
{
ServiceController[] services = ServiceController.GetServices();
foreach (ServiceController s in services)
{
if (s.ServiceName == serviceName)
{
return true;
}
}
return false;
}
#endregion #region 安装服务
private void InstallService(IDictionary stateSaver, string filepath)
{
try
{
ServiceController service = new ServiceController("ServiceName");
if (!ServiceIsExisted("ServiceName"))
{
//Install Service
AssemblyInstaller myAssemblyInstaller = new AssemblyInstaller();
myAssemblyInstaller.UseNewContext = true;
myAssemblyInstaller.Path = filepath;
myAssemblyInstaller.Install(stateSaver);
myAssemblyInstaller.Commit(stateSaver);
myAssemblyInstaller.Dispose();
//--Start Service
service.Start();
}
else
{
if (service.Status != System.ServiceProcess.ServiceControllerStatus.Running && service.Status != System.ServiceProcess.ServiceControllerStatus.StartPending)
{
service.Start();
}
}
}
catch (Exception ex)
{ }
}
#endregion #region 卸载windows服务
private void UnInstallService(string filepath)
{
try
{
if (ServiceIsExisted("ServiceName"))
{
//UnInstall Service
AssemblyInstaller myAssemblyInstaller = new AssemblyInstaller();
myAssemblyInstaller.UseNewContext = true;
myAssemblyInstaller.Path = filepath;
myAssemblyInstaller.Uninstall(null);
myAssemblyInstaller.Dispose();
}
}
catch (Exception ex)
{ }
}
#endregion public void StopService()
{
if (ServiceIsExisted("MyService"))
{
if (IsServiceStart("MyService"))
{
this.StopService("MyService");
}
} } public void StartService()
{ if (ServiceIsExisted("MyService"))
{
if (!IsServiceStart("MyService"))
{
this.StartService("MyService");
}
} }
}

总结

当有任何一个功能需要开发时先要弄懂其原理,并且能反复调试网上找来的源码,反复调试后能明白其中的原理才能更好的应用。初拿到这个功能时并不明白就想去集成,结果花了时间还没弄明白怎么使用。 再次感谢圣殿骑士和逆水寒龙的文章给我的启示。

Demo下载 提取码99a9

Winform在线更新的更多相关文章

  1. winform 自动升级

    自动升级系统OAUS的设计与实现(续) (附最新源码) http://www.cnblogs.com/zhuweisky/p/4209058.html Winform在线更新 http://www.c ...

  2. Vs2017发布可在线更新的Winform程序

    如题,此处引用“南秦岭”的博文<使用ClickOnce发布Windows应用程序>,对作者表示感谢! 补充说明: “发布文件夹”是指你电脑上的本地文件夹:“安装文件夹”是指你提供给用户的u ...

  3. 在WinForm中使用Web Service来实现软件自动升级

    来源:互联网 winform程序相对web程序而言,功能更强大编程更方便,但软件更新却相当麻烦,要到客户端一台一台地升级,面对这个实际问题,在最近的一个小项目中,本人设计了一个通过软件实现自动升级技术 ...

  4. 客户端(winform)更新

    winform更新有两种情况,一种是在线更新在线使用:直接右击项目发布出去就可以更新在线使用了.还有一种更新是不用一直连接网络的模式. 1:C#Winform程序如何发布并自动升级--------ht ...

  5. 在WinForm中使用Web Services 来实现 软件自动升级( Auto Update ) (C#)

    winform程序相对web程序而言,功能更强大,编程更方便,但软件更新却相当麻烦,要到客户端一台一台地升级,面对这个实际问题,在最近的一个小项目中,本人设计了一个通过软件实现自动升级技术方案,弥补了 ...

  6. WinForm应用程序中实现自动更新功能

    WinForm应用程序中实现自动更新功能 编写人:左丘文 2015-4-20 近来在给一客户实施ECM系统,但他们使用功能并不是我们ECM制造版提供的标准功能,他们要求对系统作一些定制功能,为了避免因 ...

  7. 在WinForm中使用Web Services 来实现 软件 自动升级( Auto Update ) (C#)

    winform程序相对web程序而言,功能更强大,编程更方便,但软件更新却相当麻烦,要到客户端一台一台地升级,面对这个实际问题,在最近的一个小项目中,本人设计了一个通过软件实现自动升级技术方案,弥补了 ...

  8. C#[WinForm]实现自动更新

    C#[WinForm]实现自动更新 winform程序相对web程序而言,功能更强大,编程更方便,但软件更新却相当麻烦,要到客户端一台一台地升级,面对这个实际问题,在最近的一个小项目中,本人设计了一个 ...

  9. 使用 .NET WinForm 开发所见即所得的 IDE 开发环境,实现不写代码直接生成应用程序

    直接切入正题,这是我09年到11年左右业余时间编写的项目,最初的想法很简单,做一个能拖拖拽拽就直接生成应用程序的工具,不用写代码,把能想到的业务操作全部封装起来,通过配置的方式把这些业务操作组织起来运 ...

随机推荐

  1. 疯狂C#~伴随着我的库存管理¥

    每次的等待都是期待下一次的勃发!但激进的我非常想和大家学习一些东西,所以特地的分享了一个库存管理, 生活中容易运用的很多,但现在的学业希望能够得到各界人士的帮助!!! 首先:会有几个类来让它们协调 ( ...

  2. Logstash之multiline 插件

    input { stdin { codec => multiline { pattern => "^\[" negate => true what => & ...

  3. eclipse构建maven的web项目

    如果以后要创建maven的web项目,可以参考这个链接 http://blog.csdn.net/smilevt/article/details/8215558/

  4. C#程序代码分析(第三周)

    刚开始看到这段程序,都不知道是什么东西,问过室友才知道是C#程序:但对C#一点都不了解,最基本的项目建设都不会,在室友的帮助下,以及在网上搜了一些资料,勉强算是完成了此次作业吧. using Syst ...

  5. CYQ.Data V5 分布式缓存MemCached应用开发介绍

    前言 今天大伙还在热议关于.NET Core的东西,我只想说一句:在.NET 跨平台叫了这么多年间,其实人们期待的是一个知名的跨平台案例,而不是一堆能跨平台的消息. 好,回头说说框架: 在框架完成数据 ...

  6. MySQL MMM高可用方案

    200 ? "200px" : this.width)!important;} --> 介绍 本篇文章主要介绍搭建MMM方案以及MMM架构的原理.这里不介绍主从.主主的搭建方 ...

  7. I/O重定向的原理和实现

    在Unix系统中,每个进程都有STDIN.STDOUT和STDERR这3种标准I/O,它们是程序最通用的输入输出方式.几乎所有语言都有相应的标准I/O函数,比如,C语言可以通过scanf从终端输入字符 ...

  8. Azure PowerShell (7) 使用CSV文件批量设置Virtual Machine Endpoint

    <Windows Azure Platform 系列文章目录> 请注意: - Azure不支持增加Endpoint Range - 最多可以增加Endpoint数量为150 http:// ...

  9. 《Entity Framework 6 Recipes》翻译系列 (3) -----第二章 实体数据建模基础之创建一个简单的模型

    第二章 实体数据建模基础 很有可能,你才开始探索实体框架,你可能会问“我们怎么开始?”,如果你真是这样的话,那么本章就是一个很好的开始.如果不是,你已经建模,并在实体分裂和继承方面感觉良好,那么你可以 ...

  10. 《Entity Framework 6 Recipes》中文翻译系列 (11) -----第三章 查询之异步查询

    翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 第三章 查询 前一章,我们展示了常见数据库场景的建模方式,本章将向你展示如何查询实体 ...