这是本人第一次写比较复杂的文章,表达不清之处,请各位见谅。好,闲话少说,入正题。
最近单位开发一个项目,其中需要用到自动升级功能。因为自动升级是一个比较常用的功能,可能会在很多程序中用到,于是,我就想写一个自动升级的组件,在应用程序中,只需要引用这个自动升级组件,并添加少量代码,即可实现自动升级功能。因为我们的程序中可能包含多个exe或者dll文件,所以要支持多文件的更新。
首先,要确定程序应该去哪里下载需要升级的文件。我选择了到指定的网站上去下载,这样比较简单,也通用一些。在这个网站上,需要放置一个当前描述最新文件列表的文件,我们估且叫它服务器配置文件。这个文件保存了当前最新文件的版本号(lastver),大小(size),下载地址(url),本地文件的保存路径(path),还有当更新了这个文件后,程序是否需要重新启动(needRestart)。这个文件大致如下:
updateservice.xml
<?xmlversion="1.0"encoding="utf-8"?>
<updateFiles>
<filepath="AutoUpdater.dll"url="http://update.iyond.com/CompanyClientApplication/AutoUpdater.zip"lastver="1.0.0.0"size="28672"needRestart="true"/>
<filepath="CompanyClient.exe"url="http://update.iyond.com/CompanyClientApplication/CompanyClient.zip"lastver="1.1.0.0"size="888832"needRestart="true"/>
<filepath="HappyFenClient.dll"url="http://update.iyond.com/CompanyClientApplication/HappyFenClient.zip"lastver="1.0.0.0"size="24576"needRestart="true"/>
<filepath="NetworkProvider.dll"url="http://update.iyond.com/CompanyClientApplication/NetworkProvider.zip"lastver="1.0.0.0"size="32768"needRestart="true"/>
<filepath="Utility.dll"url="http://update.iyond.com/CompanyClientApplication/Utility.zip"lastver="1.0.0.0"size="20480"needRestart="true"/>
<filepath="Wizard.dll"url="http://update.iyond.com/CompanyClientApplication/Wizard.zip"lastver="1.0.0.0"size="24576"needRestart="true"/>
</updateFiles>
同时,客户端也保存了一个需要升级的本地文件的列表,形式和服务器配置文件差不多,我们叫它本地配置文件。其中,<Enable>节点表示是否启用自动升级功能,<ServerUrl>表示服务器配置文件的地址。
update.config
<?xmlversion="1.0"encoding="utf-8"?>
<Configxmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Enabled>true</Enabled>
<ServerUrl>http://update.iyond.com/updateservice.xml</ServerUrl>
<UpdateFileList>
<LocalFilepath="AutoUpdater.dll"lastver="1.0.0.0"size="28672"/>
<LocalFilepath="CompanyClient.exe"lastver="1.1.0.0"size="888832"/>
<LocalFilepath="HappyFenClient.dll"lastver="1.0.0.0"size="24576"/>
<LocalFilepath="NetworkProvider.dll"lastver="1.0.0.0"size="32768"/>
<LocalFilepath="Utility.dll"lastver="1.0.0.0"size="20480"/>
<LocalFilepath="Wizard.dll"lastver="1.0.0.0"size="24576"/>
</UpdateFileList>
</Config>
使用自动各级组件的程序在启动时,会去检查这个配置文件。如果发现有配置文件中的文件版本和本地配置文件中描述的文件版本不一致,则提示用户下载。同时,如果本地配置文件中某些文件在服务器配置文件的文件列表中不存在,则说明这个文件已经不需要了,需要删除。最后,当升级完成后,会更新本地配置文件。
我们先来看一下如何使用这个组件。
在程序的Program.cs的Main函数中:
[STAThread]
staticvoidMain()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
AutoUpdaterau=newAutoUpdater();
try
{
au.Update();
}
catch(WebExceptionexp)
{
MessageBox.Show(String.Format("无法找到指定资源\n\n{0}",exp.Message),"自动升级",MessageBoxButtons.OK,MessageBoxIcon.Error);
}
catch(XmlExceptionexp)
{
MessageBox.Show(String.Format("下载的升级文件有错误\n\n{0}",exp.Message),"自动升级",MessageBoxButtons.OK,MessageBoxIcon.Error);
}
catch(NotSupportedExceptionexp)
{
MessageBox.Show(String.Format("升级地址配置错误\n\n{0}",exp.Message),"自动升级",MessageBoxButtons.OK,MessageBoxIcon.Error);
}
catch(ArgumentExceptionexp)
{
MessageBox.Show(String.Format("下载的升级文件有错误\n\n{0}",exp.Message),"自动升级",MessageBoxButtons.OK,MessageBoxIcon.Error);
}
catch(Exceptionexp)
{
MessageBox.Show(String.Format("升级过程中发生错误\n\n{0}",exp.Message),"自动升级",MessageBoxButtons.OK,MessageBoxIcon.Error);
}
Application.Run(newMainUI());
}
如上所示,只需要简单的几行代码,就可以实现自动升级功能了。
软件运行截图:



下面,我们来详细说一下这个自动升级组件的实现。
先看一下类图:

AutoUpdater:自动升级的管理类,负责整体的自动升级功能的实现。
Config:配置类,负责管理本地配置文件。
DownloadConfirm:一个对话框,向用户显示需要升级的文件的列表,并允许用户选择是否马上升级。
DownloadFileInfo:要下载的文件的信息
DownloadProgress:一个对话框,显示下载进度。
DownloadProgress.ExitCallBack,
DownloadProgress.SetProcessBarCallBack,
DownloadProgress.ShowCurrentDownloadFileNameCallBack:由于.NET2.0不允许在一个线程中访问另一个线程的对象,所以需要通过委托来实现。
LocalFile:表示本地配置文件中的一个文件
RemoteFile:表示服务器配置文件中的一个文件。
UpdateFileList:一个集合,从List<LocalFile>继承
我们先整体看一下AutoUpdater.cs:

AutoUpdater.cs
<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->
publicclassAutoUpdater


{
conststringFILENAME="update.config";
privateConfigconfig=null;
privateboolbNeedRestart=false;

publicAutoUpdater()


{
config=Config.LoadConfig(Path.Combine(AppDomain.CurrentDomain.BaseDirectory,FILENAME));
}

/**////<summary>
///检查新版本
///</summary>
///<exceptioncref="System.Net.WebException">无法找到指定资源</exception>
///<exceptioncref="System.NotSupportException">升级地址配置错误</exception>
///<exceptioncref="System.Xml.XmlException">下载的升级文件有错误</exception>
///<exceptioncref="System.ArgumentException">下载的升级文件有错误</exception>
///<exceptioncref="System.Excpetion">未知错误</exception>
///<returns></returns>
publicvoidUpdate()


{
if(!config.Enabled)
return;

/**//*
*请求Web服务器,得到当前最新版本的文件列表,格式同本地的FileList.xml。
*与本地的FileList.xml比较,找到不同版本的文件
*生成一个更新文件列表,开始DownloadProgress
*<UpdateFile>
*<Filepath=""url=""lastver=""size=""></File>
*</UpdateFile>
*path为相对于应用程序根目录的相对目录位置,包括文件名
*/
WebClientclient=newWebClient();
stringstrXml=client.DownloadString(config.ServerUrl);

Dictionary<string,RemoteFile>listRemotFile=ParseRemoteXml(strXml);

List<DownloadFileInfo>downloadList=newList<DownloadFileInfo>();

//某些文件不再需要了,删除
List<LocalFile>preDeleteFile=newList<LocalFile>();

foreach(LocalFilefileinconfig.UpdateFileList)


{
if(listRemotFile.ContainsKey(file.Path))


{
RemoteFilerf=listRemotFile[file.Path];
if(rf.LastVer!=file.LastVer)


{
downloadList.Add(newDownloadFileInfo(rf.Url,file.Path,rf.LastVer,rf.Size));
file.LastVer=rf.LastVer;
file.Size=rf.Size;

if(rf.NeedRestart)
bNeedRestart=true;
}

listRemotFile.Remove(file.Path);
}
else


{
preDeleteFile.Add(file);
}
}

foreach(RemoteFilefileinlistRemotFile.Values)


{
downloadList.Add(newDownloadFileInfo(file.Url,file.Path,file.LastVer,file.Size));
config.UpdateFileList.Add(newLocalFile(file.Path,file.LastVer,file.Size));

if(file.NeedRestart)
bNeedRestart=true;
}

if(downloadList.Count>0)


{
DownloadConfirmdc=newDownloadConfirm(downloadList);

if(this.OnShow!=null)
this.OnShow();

if(DialogResult.OK==dc.ShowDialog())


{
foreach(LocalFilefileinpreDeleteFile)


{
stringfilePath=Path.Combine(AppDomain.CurrentDomain.BaseDirectory,file.Path);
if(File.Exists(filePath))
File.Delete(filePath);

config.UpdateFileList.Remove(file);
}

StartDownload(downloadList);
}
}
}

privatevoidStartDownload(List<DownloadFileInfo>downloadList)


{
DownloadProgressdp=newDownloadProgress(downloadList);
if(dp.ShowDialog()==DialogResult.OK)


{
//更新成功
config.SaveConfig(Path.Combine(AppDomain.CurrentDomain.BaseDirectory,FILENAME));

if(bNeedRestart)


{
MessageBox.Show("程序需要重新启动才能应用更新,请点击确定重新启动程序。","自动更新",MessageBoxButtons.OK,MessageBoxIcon.Information);
Process.Start(Application.ExecutablePath);
Environment.Exit(0);
}
}
}

privateDictionary<string,RemoteFile>ParseRemoteXml(stringxml)


{
XmlDocumentdocument=newXmlDocument();
document.LoadXml(xml);

Dictionary<string,RemoteFile>list=newDictionary<string,RemoteFile>();
foreach(XmlNodenodeindocument.DocumentElement.ChildNodes)


{
list.Add(node.Attributes["path"].Value,newRemoteFile(node));
}

returnlist;
}
publiceventShowHandlerOnShow;
}
在构造函数中,我们先要加载配置文件:
publicAutoUpdater()
{
config=Config.LoadConfig(Path.Combine(AppDomain.CurrentDomain.BaseDirectory,FILENAME));
}
最主要的就是Update()这个函数了。当程序调用au.Update时,首先检查当前是否开户了自动更新:
if(!config.Enabled)
return;
如果启用了自动更新,就需要去下载服务器配置文件了:
WebClientclient=newWebClient();
stringstrXml=client.DownloadString(config.ServerUrl);
然后,解析服务器配置文件到一个Dictionary中:
Dictionary<string,RemoteFile>listRemotFile=ParseRemoteXml(strXml);
接下来比较服务器配置文件和本地配置文件,找出需要下载的文件和本地需要删除的文件:
相关推荐
### 在WinForm应用程序中实现自动升级 #### 一、引言 随着软件技术的发展与进步,用户对于软件体验的要求也越来越高。特别是在企业级应用中,软件的稳定性与更新的便捷性成为了衡量产品优劣的重要标准之一。对于...
本篇主要介绍如何使用C#在WinForm应用程序中实现自动升级。 首先,理解自动升级的基本流程: 1. **服务器端**:发布新版本的程序到服务器,并提供一个版本信息文件(如XML或JSON),包含新版本号、下载地址等。 2. ...
描述中提到,这个自动升级程序是作者为WinForm应用程序设计的,适用于任何WinForm客户端。这意味着无论你的WinForm应用是什么,只要按照一定的接口或规范进行集成,都可以利用这个自动升级程序。作者将其开源共享,...
本文将详细介绍如何使用C#和WinForm技术,结合SimpleUpdater工具来实现WinForm应用的自动升级功能。 首先,理解SimpleUpdater的基本概念。SimpleUpdater是一款轻量级的、开源的自动更新库,特别适用于小型Windows...
2. **版本控制**:在实现自动升级前,我们需要对每个发布的版本进行版本号管理,以便程序能够识别新版本。版本号应按照递增顺序设置,例如1.0.0.1、1.0.0.2等。 3. **升级组件选择**:可以选择使用现成的升级组件,...
这个文件通常会集成到你的WinForm应用程序中,当检测到有新的版本时,它会下载并安装更新,然后重新启动应用程序以加载新版本。 "AutoUpDate.xml"文件很可能是配置文件,其中包含了自动升级组件需要的各种设置,如...
在.NET框架下,WinForm应用程序的自动升级是一个重要的功能,它允许用户无痛地更新到最新版本,无需手动下载和安装。本项目标题为“WinForm自动升级程序”,结合描述和标签,我们可以深入探讨这个话题。 WinForm...
本文将详细介绍如何利用C#语言和.NET Framework来实现Winform应用程序的发布以及如何通过简单的设置实现应用程序的自动升级。 #### 发布准备阶段 1. **创建发布目录**:首先需要创建一个专门用于存放发布后程序的...
在C# WinForm应用程序开发中,自动升级和自动更新功能是至关重要的,它允许用户无需手动操作即可获取程序的最新版本。本教程将详细介绍如何利用VS2005通过HTTP协议实现这一目标。 首先,我们需要理解自动升级的基本...
针对标题“Winform开发的自动检查更新程序源码”和描述中的内容,我们可以深入探讨Winform应用程序如何实现自动检查更新的功能,以及这一功能的重要性和实现机制。 自动检查更新是现代软件系统不可或缺的一部分,它...
(2)在项目中再创建一个名为AutoUpdateTask的Winform应用程序工程,并将默认的Form1.cs窗体文件重命名为AutoUpdateTaskFrm.cs作为更新程序窗体 创建更新程序窗体 (3)在更新程序窗体中放入图上所示的相关控件; ...
"winform程序升级功能"涉及到的是如何在已部署的WinForm应用中实现自动更新和手动更新的功能。 一、自动升级 自动升级是让用户在不离开应用程序的情况下,系统自动检测并下载最新的程序版本进行更新。这一过程通常...
在C# Winform应用程序开发中,程序升级是一个重要的功能,特别是在持续迭代和更新软件时。本文将详细讨论如何设计一个Winform程序升级机制,通过数据库存储来管理版本信息。 首先,我们要理解升级程序的基本原理。...
在.NET WinForm应用程序开发中,实现自动升级功能是一项重要的任务,它能让用户无需手动下载安装新的版本,系统会自动检测并完成更新。本项目提供的代码示例深入展示了自动升级的具体实现,同时也涵盖了升级包自身的...
在.NET框架中,WinForm应用程序的自动更新是一个重要的功能,特别是在持续迭代和修复错误的情况下。本文将详细解析标题为“Winform自动更新程序源码(支持增量更新,删除文件操作)”的项目,并探讨其中涉及的关键...
这个"C# WinForm程序自动升级源码"应该包含了实现以上步骤的代码和逻辑。`使用说明.doc`文档将详细解释如何集成这个功能到你的项目中,包括设置更新服务器、配置更新路径等。文档可能还会包含错误处理和异常处理的...
在IT行业中,Windows Forms(简称WinForm)程序的自动升级是一项重要的功能,它允许应用程序在运行时检测并安装最新的更新,从而确保用户始终能够获得最新的软件版本和修复。本篇文章将详细探讨WinForm程序自动升级...
通过分析和学习这些代码,开发者可以了解到如何将这些功能集成到自己的WinForm应用程序中。 总的来说,"winform版本自动升级C#"是一个实用的工具,它帮助开发者简化了C/S模式下应用程序的更新流程,确保用户始终...
本文将基于提供的标题和描述,深入探讨如何实现C# WinForm应用的自动升级功能,并结合可能包含在"AutoUpdateExample"压缩包中的源代码进行分析。 首先,自动升级通常涉及以下几个关键步骤: 1. **检测新版本**:...