B/S架构的好处就是。UI代码的修改只需要将新的html 文件部署在服务端即可。C/S 架构客户端的修改就没有那么方便了,需要每个客户端一个一个的更新。这明显是不可能的事情,有很多客户端的时候,这种更新会要人命的。
第一种方案:自动更新就是在客户端启动的时候检测客户端有没有更新,有更新的话,下载新的客户端文件,重新安装就好。这种做法虽然比一个一个更新好多了,也减轻了实施人员的工作量,但是还是存在一个弊端,比如客户端文件我就修改了一个xml ,都要下载整个客户端文件进行重新安装,这样确实很浪费时间。
第二种方案:就是按需更新,如果客户端就需要更新一个xml 那就把xml文件放在服务端,客户端检测xml 文件有更新,只下载xml 文件即可。
所以下面就说一下第二种更新方案。
首先,服务端将客户端目录下所有文件的修改时间记录,文件路径,下来,定义一个版本号。,如果某一个文件有更新,那个这个文件的版本号就 + 1 。客户端检测的时候 首先将这个版本文件下载下来,对比本地的版本文件,看看哪一个文件的版本号码有变化,那就是这个文件有更新。根据文件路径只下载这个文件就好。
文件发布:
try { XmlDocument xmlDoc = new XmlDocument(); //Create the xml declaration first xmlDoc.AppendChild(xmlDoc.CreateXmlDeclaration("1.0", "utf-8", null)); //Create the root node and append into doc var AutoUpdate = xmlDoc.CreateElement("AutoUpdate"); xmlDoc.AppendChild(AutoUpdate); // Contact XmlElement LastUpdateTime = xmlDoc.CreateElement("LastUpdateTime"); //XmlAttribute attrID = xmlDoc.CreateAttribute("id"); LastUpdateTime.InnerText = verModle.LastTime; AutoUpdate.AppendChild(LastUpdateTime); // Contact Name XmlElement Version = xmlDoc.CreateElement("Version"); Version.InnerText = verModle.Version; AutoUpdate.AppendChild(Version); XmlElement PubNumber = xmlDoc.CreateElement("PubNumber"); PubNumber.InnerText = verModle.PubNumber; AutoUpdate.AppendChild(PubNumber); // Contact Gender XmlElement UpdateFileList = xmlDoc.CreateElement("UpdateFileList"); foreach (var item in verModle.fileDic) { XmlElement File = xmlDoc.CreateElement("File"); XmlAttribute Ver = xmlDoc.CreateAttribute("Ver"); Ver.Value = item.Value.version; File.Attributes.Append(Ver); XmlAttribute LastTime = xmlDoc.CreateAttribute("LastTime"); LastTime.Value = item.Value.lastime; File.Attributes.Append(LastTime); XmlAttribute Name = xmlDoc.CreateAttribute("Name"); Name.Value = item.Key; File.Attributes.Append(Name); XmlAttribute pubnumber = xmlDoc.CreateAttribute("PubNumber"); pubnumber.Value = item.Value.pubnumber; File.Attributes.Append(pubnumber); UpdateFileList.AppendChild(File); } AutoUpdate.AppendChild(UpdateFileList); xmlDoc.Save(itemName + "_UpdateVersion.xml"); if(File.Exists("BackUp/" + itemName + "_UpdateVersion.xml")) { File.Delete("BackUp/" + itemName + "_UpdateVersion.xml"); } File.Copy(itemName + "_UpdateVersion.xml", "BackUp/" + itemName + "_UpdateVersion.xml"); } catch(Exception ex) { MessageBox.Show("发布失败:" + ex.Message); return; } MessageBox.Show("发布成功:" + itemName + "_UpdateVersion.xml");
文件检测:
try { string root1 = AppDomain.CurrentDomain.BaseDirectory; DirectoryInfo di1 = new DirectoryInfo(root1); DirectoryInfo di2 = di1.Parent; string root = di2.FullName; LogClass.listLog.Add("root:" + root); //Directory.SetCurrentDirectory(root); bool update = false; int i = 0; foreach (var item in arrUpdate) { int len = item.ToString().IndexOf("\\", 1); len = len < 0 ? 0 : len; string strItem = item.ToString().Substring(len); //判断是否是目录 string ext = Path.GetExtension(strItem.ToString()); if (string.IsNullOrEmpty(ext)) { try { if (!Directory.Exists(root + strItem)) { Directory.CreateDirectory(root + strItem); this.labelUpdatePath.Invoke((EventHandler)delegate { labelUpdatePath.Text = strItem.ToString(); //listBoxTip.Items.Add(item.ToString()); }); } } catch { } } else { if(item.ToString().IndexOf("AutoUpdate.exe")>=0 && item.ToString().IndexOf("AutoUpdate.exe.config") < 0) { strItem = strItem + ".0"; } bool ret = HttpHelper.HttpDownload(httpDownloadAddress + item.ToString(), root + strItem.ToString() + ".ttemp"); //bool ret = ftp.Download(root, item.ToString(),item.ToString().Substring(item.ToString().IndexOf("\\",1))); if (ret) { this.labelUpdatePath.Invoke((EventHandler)delegate { labelUpdatePath.Text = strItem.ToString(); }); } else { updateSuccess = false; LogClass.listLog.Add("download file error:" + strItem.ToString()); } } i++; this.progressBar1.Invoke((EventHandler)delegate { progressBar1.Value = i; }); //listBoxTip.TopIndex = listBoxTip.Items.Count - 1; } this.Invoke((EventHandler)delegate { //开始删除 bool ret = DealAfterUpdate(root); if(!ret) { throw new Exception("DealAfterUpdate error"); } if (File.Exists(root1 + "UpdateVersion.xml")) { File.Delete(root1 + "UpdateVersion.xml"); } Thread.Sleep(100); File.Move(root1 + updateFile, root1 + "UpdateVersion.xml"); if(File.Exists(root1 + "BackUp/UpdateVersion.xml")) { File.Delete(root1 + "BackUp/UpdateVersion.xml"); } File.Copy(root1 + "UpdateVersion.xml", root1 + "BackUp/UpdateVersion.xml"); //操作完成之后,在启动之前看看还是否需要有其他操作要执行 foreach(string item in excuteAfterUpdate.Split(',')) { if (!string.IsNullOrEmpty(item)) { LogClass.listLog.Add("ExcuteUpdate:" + root1 + item); Process process = new Process(); process.StartInfo.FileName = root1 + item; process.StartInfo.Arguments = ""; process.Start(); process.WaitForExit(); } } if (isStartAfterUpdate == "1") { Process.Start(root1 + updateProcessPath); } if (this.args[0] == "1") { MessageBox.Show("更新完成"); } this.Close(); }); } catch (Exception e) { this.Invoke((EventHandler)delegate { MessageBox.Show("更新失败"); }); LogClass.listLog.Add("thread error:" + e.Message); } updating = false;
并且该自动更新插件,不挑剔任何客户端,只要哪个客户端需要自动更新,那就很方便的可以集成进去,已经运用在实际项目中,解决了很多复杂的工作。
同时呢,自动更新exe 最近也解决了,更新本身这个问题。