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 最近也解決了,更新本身這個問題。