自動升級的原理及實現

  C/S程序自動升級是一個很重要的功能,原理其實很簡單,通常包含兩個程序一個是主程序,也就是除了升級功能之外的程序,另外一個就是升級程序,常見的360,金山安全衛士都是這樣。html

 主要包括如下幾點:   1 比較版本  2下載文件  3更新文件 4啓動主程序。但其中的須要注意的細節不少。 web

    通常服務端會有一個配置文件包含最新更新的文件信息的配置文件,固然這些更新信息也能夠存到數據庫,或者其餘地方。客戶端(也就是須要更新的那部分程序)也有一個配置文件包含客戶端版本信息,這些信息能夠存到專門的一個配置文件中,或者是config文件中,沒有必定的規定,能夠根據實際設計。數據庫

   在客戶端程序啓動時,先啓動更新程序經過比較本地版本和服務端最新的版本信息判斷是否有新版本,若是有能夠直接下載,下載完成替換成功後並更新客戶端版本信息,啓動主程序。windows

            缺點:若是更新速度因爲更新的文件很大或者網速很慢,用戶不得不等待很長時間,直到下載完成或者下載失敗。安全

            優勢:處理完成後,啓動的直接就是更新後的程序。不會出現因爲主程序在運行致使替換文件時提示文件在使用,不能替換之類的錯誤。服務器

   另外一種方法是, 在客戶端段程序啓動時,啓動更新程序,但更新程序不作版本判斷,到客戶端更新目錄下檢查有沒有下載的新版本,若是有就更新主程序並更新客戶端版本信息,而後啓動主程序,若是沒有就直接啓動主程序。由主程序判斷是否有新版本,並在後臺下載把文件放到客戶端更新目錄中,下載完成後,提示用戶退出主程序,從新啓動,在啓動時由更新程序並更新客戶端和客戶端版本信息。    性能

            缺點:因爲下載是在主程序的後臺運行,可能會影響主程序的處理速度。網站

            優勢:避免了因爲下載致使用戶長時間的等待。ui

1 比較版本this

    比較依據:

    能夠經過文件的最後修改時間,或者使用文件版本做爲比較依據,使用文件最後修改時間顯然不是標準的作法,但也沒有錯誤,但須要注意日期的格式必定要統一,避免日  期格式不一致致使錯誤。可使用Fileinfo類獲取最後修改時間,注意時間應該取服務器時間,編譯程序集的機器時間應該相同,不然可能致使混亂。

FIleInfo類官網參考

   使用文件版本做爲標準,則每次修改時必須修改版本號,C#程序就是要修AssemblyInfo.cs文件中的內容了,多了一步,規範多了。Version類處理版本信息並比較。 

[csharp]  view plain copy
 
  1. Assembly thisAssem = Assembly.GetExecutingAssembly();  
  2.      AssemblyName thisAssemName = thisAssem.GetName();  
  3.      Version ver = thisAssemName.Version;  

Version類官網參考

  固然也有其餘的方式,例如MD5校驗值比較,文件大小比較,之類的方法。不過我的認爲文件大小缺陷很明顯,新版本文件就必定比舊文件大嗎?不必定吧。重構是可能變小的。

固然若是考慮客戶端有不一樣的版本,都須要升級到最新的版本,顯然不一樣的版本對應的升級文件不一樣,會更復雜,比較的信息也更多。

   獲取服務端版本信息:

    若是服務端的版本信息存在數據庫,直接讀取數據庫,就能夠獲取。若是存在配置文件,則能夠經過webservice方法獲取,或者請求一個網頁 經過Response.Write();的方式獲取信息,固然這兩種方式都要創建虛擬目錄或者網站。

2下載文件

  存儲位置:

     若是新版本的文件存在數據庫,就直接讀取數據庫,不過這種方式我的不建議使用,例如更新文件很大時性能不是很好。

    存在固定虛擬目錄的指定路徑下,不失爲一種好的方式,但客戶端要下載,因此要注意必定要分配下載權限。

下載方式:

   直接向經過虛擬路徑發出請求,下載文件,因爲虛擬路徑有下載權限,若是更新須要判斷是否有權限,例如要交費後才能下載則很差處理。

  另外一種方式是向一個網頁發送請求,傳遞不一樣的查詢字符串,網頁 經過Response.BinaryWrite();的方式下載文件,則能夠判斷權限,固然麻煩一些是避免不了的。

下載文件代碼

[csharp]  view plain copy
 
  1. Uri uri = new Uri(downFileUrl + localFileName);  
  2.               HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);  
  3.               request.Credentials = CredentialCache.DefaultCredentials;  
  4.               request.MaximumAutomaticRedirections = 4;  
  5.               localFileName = Path.GetFileName(localFileName);  
  6.               using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())  
  7.               {  
  8.                   Stream receiveStream = response.GetResponseStream();  
  9.                   string newPath = Path.Combine(tempFold, localFileName);  
  10.                   using (FileStream fs = new FileStream(newPath, FileMode.Create))  
  11.                   {  
  12.                       Byte[] buffer = new Byte[4096];  
  13.                       int bytesRead = receiveStream.Read(buffer, 0, buffer.Length);  
  14.                       while (bytesRead > 0){  
  15.                           fs.Write(buffer, 0, bytesRead);  
  16.                           bytesRead = receiveStream.Read(buffer, 0, buffer.Length);  
  17.                       }  
  18.                   }  
  19.                   receiveStream.Close();  
  20.               }  

3更新文件

      更新類型:

     直接替換的,例如修改了bug,直接替換的。

     新增長的,例如新增長的功能作成了新的類庫。

    須要刪除的,例若有些功能因爲重構或者使用了了新方法不須要的。

     須要執行的,例如寫註冊表,註冊COM組件的。

     每一種處理方式都不同,須要根據類型分開處理

     缺點:升級後,沒辦法取消升級,像windows的補丁程序能夠安裝,能夠卸載的原理,目前尚未研究明白,但願知道的牛人指導。

    固然也能夠簡單的先卸載,再安裝,對於配置文件之類的信息特殊處理一下也能夠。

   固然若是考慮客戶端有不一樣的版本,都須要升級到最新的版本,顯然不一樣的版本對應的升級文件不一樣,會更復雜,但基本原理卻不變。

4啓動主程序

  主程序路徑的獲取:

   相對路徑   主程序,更新程序,都使用相對路徑,缺點是一旦相對路徑肯定後,後續的更新就不能更改這種目錄關係。

  註冊表  路徑都存入註冊表,須要時經過註冊表交互,主程序寫註冊表,更新程序讀取註冊表,缺點是讀寫註冊表須要權限,寫的路徑也要固定,後續的更新不能改變寫在註冊表中的位置,也就是註冊表路徑。

運行程序代碼

 

[csharp]  view plain copy
 
  1. private static void RunFile(string dir, string localFileName){  
  2.           string info = "運行程序" + localFileName;  
  3.           try{  
  4.               if (File.Exists(Path.Combine(dir, localFileName))){  
  5.                   Process myProcess = new Process();  
  6.                   ProcessStartInfo psi = new ProcessStartInfo();  
  7.                   psi.FileName = localFileName;  
  8.                   psi.WorkingDirectory = dir;  
  9.                   psi.UseShellExecute = false;  
  10.                   psi.RedirectStandardError = true;  
  11.                   psi.CreateNoWindow = true;  
  12.                   psi.RedirectStandardOutput = true;  
  13.                   psi.WindowStyle = ProcessWindowStyle.Hidden;  
  14.                   myProcess.StartInfo = psi;  
  15.                   myProcess.Start();  
  16.   
  17.                   string error = myProcess.StandardError.ReadToEnd();  
  18.                   string output = myProcess.StandardOutput.ReadToEnd();  
  19.                   myProcess.WaitForExit();  
  20.                   myProcess.Close();  
  21.                   if (error != string.Empty){  
  22.                    Log.Write("StandardError:" + error);  
  23.                   }  
  24.                   if (output != string.Empty){  
  25.                       Log.Write("StandardOutput:" + output);  
  26.                   }  
  27.                   Log.LogProcessEnd(info);  
  28.               }  
  29.           }  
  30.           catch (Exception ex){  
  31.              Log.Write(info + "出錯");  
  32.              Log.LogException(ex);  
  33.               throw ex;  
  34.           }  
  35.       }  
  36.   }  

源代碼下載

參考文章

參考文章2

參考文章3

相關文章
相關標籤/搜索