读书人

c# 智能升格程序代码(1)

发布时间: 2012-10-12 10:17:04 作者: rapoo

c# 智能升级程序代码(1)
<updateFiles>
<file path="AutoUpdater.dll" url="http://update.iyond.com/CompanyClientApplication/AutoUpdater.zip" lastver="1.0.0.0" size="28672" needRestart="true" />
<file path="CompanyClient.exe" url="http://update.iyond.com/CompanyClientApplication/CompanyClient.zip" lastver="1.1.0.0" size="888832 " needRestart="true" />
<file path="HappyFenClient.dll" url="http://update.iyond.com/CompanyClientApplication/HappyFenClient.zip" lastver="1.0.0.0" size="24576" needRestart="true" />
<file path="NetworkProvider.dll" url="http://update.iyond.com/CompanyClientApplication/NetworkProvider.zip" lastver="1.0.0.0" size="32768" needRestart="true" />
<file path="Utility.dll" url="http://update.iyond.com/CompanyClientApplication/Utility.zip" lastver="1.0.0.0" size="20480" needRestart="true" />
<file path="Wizard.dll" url="http://update.iyond.com/CompanyClientApplication/Wizard.zip" lastver="1.0.0.0" size="24576" needRestart="true" />
</updateFiles>

同时,客户端也保存了一个需要升级的本地文件的列表,形式和服务器配置文件差不多,我们叫它本地配置文件。其中,<Enable>节点表示是否启用自动升级功能,<ServerUrl>表示服务器配置文件的地址。
update.config
<?xml version="1.0" encoding="utf-8"?>
<Config xmlns: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>
??? <LocalFile path="AutoUpdater.dll" lastver="1.0.0.0" size="28672" />
??? <LocalFile path="CompanyClient.exe" lastver="1.1.0.0" size="888832 " />
??? <LocalFile path="HappyFenClient.dll" lastver="1.0.0.0" size="24576" />
??? <LocalFile path="NetworkProvider.dll" lastver="1.0.0.0" size="32768" />
??? <LocalFile path="Utility.dll" lastver="1.0.0.0" size="20480" />
??? <LocalFile path="Wizard.dll" lastver="1.0.0.0" size="24576" />
</UpdateFileList>
</Config>

使用自动各级组件的程序在启动时,会去检查这个配置文件。如果发现有配置文件中的文件版本和本地配置文件中描述的文件版本不一致,则提示用户下载。同时,如果本地配置文件中某些文件在服务器配置文件的文件列表中不存在,则说明这个文件已经不需要了,需要删除。最后,当升级完成后,会更新本地配置文件。

我们先来看一下如何使用这个组件。
在程序的Program.cs的Main函数中:

[STAThread]
static void Main()
{
??? Application.EnableVisualStyles();
??? Application.SetCompatibleTextRenderingDefault(false);

??? AutoUpdater au = new AutoUpdater();
??? try
??? {
??????? au.Update();
??? }
??? catch (WebException exp)
??? {
??????? MessageBox.Show(String.Format("无法找到指定资源\n\n{0}", exp.Message), "自动升级", MessageBoxButtons.OK, MessageBoxIcon.Error);
??? }
??? catch (XmlException exp)
??? {
??????? MessageBox.Show(String.Format("下载的升级文件有错误\n\n{0}", exp.Message), "自动升级", MessageBoxButtons.OK, MessageBoxIcon.Error);
??? }
??? catch (NotSupportedException exp)
??? {
??????? MessageBox.Show(String.Format("升级地址配置错误\n\n{0}", exp.Message), "自动升级", MessageBoxButtons.OK, MessageBoxIcon.Error);
??? }
??? catch (ArgumentException exp)
??? {
??????? MessageBox.Show(String.Format("下载的升级文件有错误\n\n{0}", exp.Message), "自动升级", MessageBoxButtons.OK, MessageBoxIcon.Error);
??? }
??? catch (Exception exp)
??? {
??????? MessageBox.Show(String.Format("升级过程中发生错误\n\n{0}", exp.Message), "自动升级", MessageBoxButtons.OK, MessageBoxIcon.Error);
??? }

??? Application.Run(new MainUI());
}

如上所示,只需要简单的几行代码,就可以实现自动升级功能了。

软件运行截图:

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

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

我们先整体看一下AutoUpdater.cs:

public class AutoUpdater
{
??? const string FILENAME = "update.config";
??? private Config config = null;
??? private bool bNeedRestart = false;

??? public AutoUpdater()
??? {
??????? config = Config.LoadConfig(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, FILENAME));
??? }
??? /**/
??? /// <summary>
??? /// 检查新版本
??? /// </summary>
??? /// <exception cref="System.Net.WebException">无法找到指定资源</exception>
??? /// <exception cref="System.NotSupportException">升级地址配置错误</exception>
??? /// <exception cref="System.Xml.XmlException">下载的升级文件有错误</exception>
??? /// <exception cref="System.ArgumentException">下载的升级文件有错误</exception>
??? /// <exception cref="System.Excpetion">未知错误</exception>
??? /// <returns></returns>
??? public void Update()
??? {
??????? if (!config.Enabled)
??????????? return;
??????? /**/
??????? /*
???? * 请求Web服务器,得到当前最新版本的文件列表,格式同本地的FileList.xml。
???? * 与本地的FileList.xml比较,找到不同版本的文件
???? * 生成一个更新文件列表,开始DownloadProgress
???? * <UpdateFile>
???? * <File path="" url="" lastver="" size=""></File>
???? * </UpdateFile>
???? * path为相对于应用程序根目录的相对目录位置,包括文件名
???? */
??????? WebClient client = new WebClient();
??????? string strXml = client.DownloadString(config.ServerUrl);

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

??????? List<DownloadFileInfo> downloadList = new List<DownloadFileInfo>();

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

??????? foreach (LocalFile file in config.UpdateFileList)
??????? {
??????????? if (listRemotFile.ContainsKey(file.Path))
??????????? {
??????????????? RemoteFile rf = listRemotFile[file.Path];
??????????????? if (rf.LastVer != file.LastVer)
??????????????? {
??????????????????? downloadList.Add(new DownloadFileInfo(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 (RemoteFile file in listRemotFile.Values)
??????? {
??????????? downloadList.Add(new DownloadFileInfo(file.Url, file.Path, file.LastVer, file.Size));
??????????? config.UpdateFileList.Add(new LocalFile(file.Path, file.LastVer, file.Size));

??????????? if (file.NeedRestart)
??????????????? bNeedRestart = true;
??????? }

??????? if (downloadList.Count > 0)
??????? {
??????????? DownloadConfirm dc = new DownloadConfirm(downloadList);

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

??????????? if (DialogResult.OK == dc.ShowDialog())
??????????? {
??????????????? foreach (LocalFile file in preDeleteFile)
??????????????? {
??????????????????? string filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, file.Path);
??????????????????? if (File.Exists(filePath))
??????????????????????? File.Delete(filePath);

??????????????????? config.UpdateFileList.Remove(file);
??????????????? }

??????????????? StartDownload(downloadList);
??????????? }
??????? }
??? }

??? private void StartDownload(List<DownloadFileInfo> downloadList)
??? {
??????? DownloadProgress dp = new DownloadProgress(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);
??????????? }
??????? }
??? }

??? private Dictionary<string, RemoteFile> ParseRemoteXml(string xml)
??? {
??????? XmlDocument document = new XmlDocument();
??????? document.LoadXml(xml);

??????? Dictionary<string, RemoteFile> list = new Dictionary<string, RemoteFile>();
??????? foreach (XmlNode node in document.DocumentElement.ChildNodes)
??????? {
??????????? list.Add(node.Attributes["path"].Value, new RemoteFile(node));
??????? }

??????? return list;
??? }
??? public event ShowHandler OnShow;
}

在构造函数中,我们先要加载配置文件:

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


读书人网 >C#

热点推荐