可複用的自動升級系統實現

來源:互聯網
上載者:User

相對於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系統實現的原始碼將在下期文章給出。


本文引用地址: http://blog.csdn.net/zhuweisky/services/trackbacks/415474.aspx

        上一篇文章解決了實現可複用的自動升級系統的思路,這篇文章將給出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;  
  }

好了,主要的實現代碼都給出來了,如果你想擷取UpdateActionSystem.exe的完整來源程式,可以email向我索取!sky.zhuwei@163.com

本文引用地址: http://blog.csdn.net/zhuweisky/services/trackbacks/415487.aspx

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.