http://blog.csdn.net/xuexiaodong2009/article/details/6640323
C/S程序自動升級是一個很重要的功能,原理其實很簡單,一般包含兩個程序一個是主程序,也就是除了升級功能以外的程序,另一個就是升級程序,常見的360,金山安全衛士都是這樣。
主要包括以下幾點: 1 比較版本 2下載文件 3更新文件 4啓動主程序。但其中的需要注意的細節很多。
一般服務端會有一個配置文件包含最新更新的文件信息的配置文件,當然這些更新信息也可以存到數據庫,或者其他地方。客戶端(也就是需要更新的那部分程序)也有一個配置文件包含客戶端版本信息,這些信息可以存到專門的一個配置文件中,或者是config文件中,沒有一定的規定,可以根據實際設計。
在客戶端程序啓動時,先啓動更新程序通過比較本地版本和服務端最新的版本信息判斷是否有新版本,如果有可以直接下載,下載完成替換成功後並更新客戶端版本信息,啓動主程序。
缺點:如果更新速度由於更新的文件很大或者網速很慢,用戶不得不等待很長時間,直到下載完成或者下載失敗。
優點:處理完成後,啓動的直接就是更新後的程序。不會出現由於主程序在運行導致替換文件之類的錯誤。
另一種方法是, 在客戶端段程序啓動時,啓動更新程序,但更新程序不做版本判斷,到客戶端更新目錄下檢查有沒有下載的新版本,如果有就更新主程序並更新客戶端版本信息,然後啓動主程序,如果沒有就直接啓動主程序。由主程序判斷是否有新版本,並在後臺下載把文件放到客戶端更新目錄中,下載完成後,提示用戶退出主程序,重新啓動,在啓動時由更新程序並更新客戶端和客戶端版本信息。
缺點:由於下載是在主程序的後臺運行,可能會影響主程序的處理速度。
優點:避免了由於下載導致用戶長時間的等待。
1 比較版本
比較依據:
可以通過文件的最後修改時間,或者使用文件版本作爲比較依據,使用文件最後修改時間顯然不是標準的做法,但也沒有錯誤,但需要注意日期的格式一定要統一,避免日 期格式不一致導致錯誤。可以使用Fileinfo類獲取最後修改時間。
FIleInfo類官網參考
http://forum.csdn.net/PointForum/Forum/PostTopic.aspx?forumID=e2798a59-79d5-4833-9c57-87d46a8b907a
使用文件版本作爲標準,則每次修改時必須修改版本號,C#程序就是要修AssemblyInfo.cs文件中的內容了,多了一步,規範多了。Version類處理版本信息並比較。
- C# code
-
Assembly thisAssem = Assembly.GetExecutingAssembly(); AssemblyName thisAssemName = thisAssem.GetName(); Version ver = thisAssemName.Version;
Version類官網參考
http://msdn.microsoft.com/zh-cn/library/system.version.aspx
當然也有其他的方式,例如MD5校驗值比較,文件大小比較,之類的方法。不過個人認爲文件大小缺陷很明顯,新版本文件就一定比舊文件大嗎?不一定吧。重構是可能變小的。
當然如果考慮客戶端有不同的版本,都需要升級到最新的版本,顯然不同的版本對應的升級文件不同,會更復雜,比較的信息也更多。
獲取服務端版本信息:
如果服務端的版本信息存在數據庫,直接讀取數據庫,就可以獲取。如果存在配置文件,則可以通過webservice方法獲取,或者請求一個網頁 通過Response.Write();的方式獲取信息,當然這兩種方式都要建立虛擬目錄或者網站。
2下載文件
存儲位置:
如果新版本的文件存在數據庫,就直接讀取數據庫,不過這種方式個人不建議使用,例如更新文件很大時性能不是很好。
存在固定虛擬目錄的指定路徑下,不失爲一種好的方式,但客戶端要下載,所以要注意一定要分配下載權限。
下載方式:
直接向通過虛擬路徑發出請求,下載文件,由於虛擬路徑有下載權限,如果更新需要判斷是否有權限,例如要交費後才能下載則不好處理。
另一種方式是向一個網頁發送請求,傳遞不同的查詢字符串,網頁 通過Response.BinaryWrite();的方式下載文件,則可以判斷權限,當然麻煩一些是避免不了的。
下載文件代碼
- C# code
-
Uri uri = new Uri(downFileUrl + localFileName); HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri); request.Credentials = CredentialCache.DefaultCredentials; request.MaximumAutomaticRedirections = 4; localFileName = Path.GetFileName(localFileName); using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) { Stream receiveStream = response.GetResponseStream(); string newPath = Path.Combine(tempFold, localFileName); using (FileStream fs = new FileStream(newPath, FileMode.Create)) { Byte[] buffer = new Byte[4096]; int bytesRead = receiveStream.Read(buffer, 0, buffer.Length); while (bytesRead > 0){ fs.Write(buffer, 0, bytesRead); bytesRead = receiveStream.Read(buffer, 0, buffer.Length); } } receiveStream.Close(); }
3更新文件
更新類型:
直接替換的,例如修改了bug,直接替換的。
新增加的,例如新增加的功能做成了新的類庫。
需要刪除的,例如有些功能由於重構或者使用了了新方法不需要的。
需要執行的,例如寫註冊表,註冊COM組件的。
每一種處理方式都不一樣,需要根據類型分開處理
缺點:升級後,沒辦法取消升級,像windows的補丁程序可以安裝,可以卸載的原理,目前還沒有研究明白,希望知道的牛人指導。
當然也可以簡單的先卸載,再安裝,對於配置文件之類的信息特殊處理一下也可以。
當然如果考慮客戶端有不同的版本,都需要升級到最新的版本,顯然不同的版本對應的升級文件不同,會更復雜,但基本原理卻不變。
4啓動主程序
主程序路徑的獲取:
相對路徑 主程序,更新程序,都使用相對路徑,缺點是一旦相對路徑確定後,後續的更新就不能更改這種目錄關係。
註冊表 路徑都存入註冊表,需要時通過註冊表交互,主程序寫註冊表,更新程序讀取註冊表,缺點是讀寫註冊表需要權限,寫的路徑也要固定,後續的更新不能改變寫在註冊表中的位置,也就是註冊表路徑。
運行程序代碼
- C# code
-
private static void RunFile(string dir, string localFileName){ string info = "運行程序" + localFileName; try{ if (File.Exists(Path.Combine(dir, localFileName))){ Process myProcess = new Process(); ProcessStartInfo psi = new ProcessStartInfo(); psi.FileName = localFileName; psi.WorkingDirectory = dir; psi.UseShellExecute = false; psi.RedirectStandardError = true; psi.CreateNoWindow = true; psi.RedirectStandardOutput = true; psi.WindowStyle = ProcessWindowStyle.Hidden; myProcess.StartInfo = psi; myProcess.Start(); string error = myProcess.StandardError.ReadToEnd(); string output = myProcess.StandardOutput.ReadToEnd(); myProcess.WaitForExit(); myProcess.Close(); if (error != string.Empty){ Log.Write("StandardError:" + error); } if (output != string.Empty){ Log.Write("StandardOutput:" + output); } Log.LogProcessEnd(info); } } catch (Exception ex){ Log.Write(info + "出錯"); Log.LogException(ex); throw ex; } } }
源代碼下載
http://download.csdn.net/source/3477103