C# Winform实现可复用的自动升级系统

相对于B/S结构来说,C/S模式的客户端的部署和升级是一个很大的麻烦。有很多企业用户就是因为这个原因而放弃使用C/S。然而当一个应用必须要使用C/S结构才能很好的实现其功能的时候,我们该如何解决客户端的部署与自动升级问题了?

部署很简单,只要点击安装程序即可,难的在于每当有新版本发布时,能够实现自动升级。首先,我需要把自动升级的概念扩展一下。自动升级不仅仅是把当前版本的主程序EXE或其使用dll自动升级新的版本,还包括,当新版本的EXE需要使用原先不存在的dll时,自动升级系统也能够自动下载这些新的dll,再进一步,自动升级系统还能删除那些不再使用的dll。

我们的目标很简单,我们希望开发一个与具体应用无关的能够复用的自动升级系统,我将它称为UpdateActionSystem。

一般我们C/S的客户端有一个主应用程序EXE和一系列辅助的DLL组成,另外还可能包括必要的配置文件和其它资源文件,为了能实现所有这些文件的自动更新,我们引入UpdateActionSystem.exe和一个版本配置文件UpdateConfig.xml放在与主程序EXE相同的目录中。UpdateConfig.xml中有当前目录下所有文件的当前版本。那么UpdateActionSystem.exe从何处获取每个文件最新的版本号了?对,从数据库。UpdateConfig.xml中给出了该数据库的位置信息。先看看UpdateConfig.xml的内容。

 
 
<?xml version="1.0" encoding="gb2312"?> <GTPDef xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <HostInfo> <DataBaseIP>218.201.34.117</DataBaseIP> <DataBaseName>haonet</DataBaseName> <SoftwareType>OASystem</SoftwareType> <CommonSoftwareTypeName>Common</CommonSoftwareTypeName> </HostInfo> <VersionInfo> <GoldPrinter.dll>2.000</GoldPrinter.dll> <XSkyControls.dll>1.000</XSkyControls.dll> <OASystem.exe>0.995</OASystem.exe> </VersionInfo> </GTPDef>

可以看到,在这个示例中,我的客户端系统有一个主程序OASystem.exe ,和两个dll--GoldPrinter.dll ,XSkyControls.dll,它们的版本号也记录于此。另外HostInfo部分记录了UpdateActionSystem.exe应该从何处获取最新版本号信息,其中的SoftwareType字段和CommonSoftwareTypeName字段在有多个不同的客户端系统都需要升级时会作为区别标志。

好,我们知道了可以从数据库中的SoftwareVersion表获取最新版本信息,我们可以看看这个表的结构:
SoftwareName -- 更新文件的名称。
URL -- 下载该文件的地址。
Version -- 该文件的最新版本号
SoftwareType -- 文件类型(与上面的配置文件中的对应)

所以当UpdateActionSystem.exe从数据库中获取的版本号必当前版本号要高,那么它就会从URL指示的地方下载新的文件。另外,如果UpdateActionSystem.exe发现数据库中的表中有一个文件的SoftwareType与配置文件中的值相同,而此文件的信息在配置文件中又不存在,说明这个文件是新加入的,于是UpdateActionSystem.exe就下载这个文件。

可以看出,我们基本把如何实现一个可复用的自动升级系统的思路已经清楚了,它是与应用无关的。
如果我们的一套系统需要引入自动升级,只需一下几个步骤:
(1)引入UpdateActionSystem.exe和一个版本配置文件UpdateConfig.xml放在与主程序EXE相同的目录中,并修改UpdateConfig.xml中的内容与当前应用一致。
(2)在数据库中增加SoftwareVersion表,并填入相应的文件信息记录。
(3)将以后新版本的文件放在数据库中URL指示的地方。
(4)在主程序中添加一个对自己的最新版本检查,如果发现有新版本,则启动UpdateActionSystem.exe。

(一般将主程序作为升级的触发器,这是以为主程序更新了,其它的dll文件可能没有更新,但是如果一个dll更新了,则主程序必定发生变化。当然你也可以直接点击UpdateActionSystem.exe进行更新。)

看看我的示例运行的图片。

当有新版本时,界面如下:


点击蓝色链接后,即执行UpdateActionSystem.exe,界面如下:


升级结束后,界面如下:


关于整个UpdateActionSystem.exe系统实现的源代码将在下期文章给出。

UpdateActionSystem.exe的主窗体UpdatingForm的主要成员如下:

 
 
private UpdateConfigParser updateParser = null ;//用于解析版本配置文件UpdateConfig.xml private DealSoftwareVersion dealVersion = null ;//用于访问数据库的SoftwareVersion表 private string curApppath = null ; // 当前路径 //构造函数中初始化各成员 #region ctor public UpdatingForm() { InitializeComponent(); this.curApppath = System.IO.Directory.GetParent(Application.ExecutablePath).ToString(); this.progressControl2.SetIDealEvent(this ) ; this.updateParser = new UpdateConfigParser(this.curApppath + "\\UpdateConfig.xml" ) ; string connStr = ...... ; this.dealVersion = new DealSoftwareVersion(connStr) ; } #endregion
下载新版本文件的线程:
 
 
#region DownloadThread private void DownloadThread() { int succeedCount = 0 ; int failCount = 0 ; SoftwareVersion[] versions = null ; try { versions = (SoftwareVersion[])this.dealVersion.GetObjects("" ) ; if((versions == null) || (versions.Length == 0 )) { MessageBox.Show("没有任何文件需要升级!" ) ; this .Close() ; } } catch { MessageBox.Show( "无法与数据库服务器建立连接,可能是服务器已关闭!升级失败!" ) ; this .Close() ; } for(int i=0 ;i<versions.Length ;i++ ) { if((versions[i].SoftwareType != this.updateParser.SoftwareType) && (versions[i].SoftwareType != this .updateParser.CommonSoftwareTypeName)) { continue ; } string softName = versions[i].SoftwareName ; decimal newVer = versions[i].Version ; string url = versions[i].URL ; string filePath = this.curApppath + "\\" + softName ; bool isExit = this .updateParser.IsSoftwareExit(softName) ; if (isExit) { decimal oldVer = this .updateParser.GetSoftwareVersion(softName) ; if(oldVer < newVer) //覆盖旧文件 { this.SetTitle(softName ,true ) ; bool succeed = this.DownLoadOneFile(url ,filePath ,this .progressControl2) ; if (succeed) { this .updateParser.SetNewVersion(softName ,newVer) ; ++ succeedCount ; this.DisplayMsg(string.Format("成功升级{0}文件!" ,softName)) ; } else { ++ failCount ; this.DisplayMsg(string.Format("升级{0}文件失败!" ,softName)) ; } } } else //下载新文件 { this.SetTitle(softName ,false ) ; this .updateParser.AddNewSoftware(softName ,newVer) ; bool succeed = this.DownLoadOneFile(url ,filePath ,this .progressControl2) ; if (succeed) { ++ succeedCount ; this.DisplayMsg(string.Format("成功下载{0}文件!" ,softName)) ; } else { ++ failCount ; this.updateParser.SetNewVersion(softName ,0 ) ; this.DisplayMsg(string.Format("下载{0}文件失败!" ,softName)) ; } } } string msg = null ; if(succeedCount+failCount == 0 ) { msg = "没有任何文件需要更新!" ; } else if((succeedCount > 0) && (failCount == 0 )) { msg = string.Format("成功更新{0}个文件!" ,succeedCount) ; } else { msg = string.Format("总共需要更新{0}个文件,成功更新{1}个文件!有{2}个文件更新失败!" , succeedCount+ failCount ,succeedCount ,failCount) ; } MessageBox.Show(msg) ; this .Close() ; } #endregion
下载某个文件的方法:
 
 
#region DownLoadOneFile private bool DownLoadOneFile(string url ,string filePath ,ProgressControl proControl) { FileStream fstream = new FileStream(filePath ,FileMode.Create ,FileAccess.Write); WebRequest wRequest = WebRequest.Create(url); try { WebResponse wResponse = wRequest.GetResponse(); int contentLength =(int )wResponse.ContentLength; byte[] buffer = new byte[1024 ]; int read_count = 0 ; int total_read_count = 0 ; bool complete = false ; proControl.SetParas(0 ,contentLength ,buffer.Length) ; while (! complete ) { read_count = wResponse.GetResponseStream().Read(buffer,0 ,buffer.Length); if(read_count > 0 ) { fstream.Write(buffer ,0 ,read_count) ; total_read_count += read_count ; if(total_read_count <= contentLength) proControl.step_forward() ; } else { complete = true ; } } fstream.Flush() ; return true ; } catch (Exception ee) { ee = ee ; return false ; } finally { fstream.Close() ; wRequest = null ; } } #endregion //在窗体加载时,启动下载线程 #region Form1_Load private void Form1_Load(object sender, System.EventArgs e) { System.Threading.Thread.Sleep(1000 ) ; ThreadDelegate thread = new ThreadDelegate(this .DownloadThread) ; thread.BeginInvoke(null ,false) ; //异步执行 } #endregion

UpdateActionSystem.exe的主要实现代码就是这些,下面给出主应用程序中的相关代码:

在登录窗体的构造函数中:

 
 
//检查自动更新 bool needUpdate = this .NeedToUpdate() ; this.linkLabel_update.Visible = needUpdate ; this.button_logon.Enabled = (! needUpdate) ; //点击linkLabel_update将启动UpdateActionSystem.exe private void linkLabel_update_LinkClicked(object sender, System.Windows.Forms.LinkLabel_updateClickedEventArgs e) { Process downprocess = new Process(); string apppath = System.IO.Directory.GetParent(Application.ExecutablePath).ToString(); downprocess.StartInfo.FileName = string.Format("{0}\\{1}" , apppath ,UpdateActionSystem.exe) ; downprocess.Start(); this.DialogResult = DialogResult.Cancel; return ; }
以上介绍的是C# Winform实现可复用的自动升级系统,希望对你了解程序升级有所帮助。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值