(本文名字取為“伺服器系統自動更新”,實際上适用于所有應用程式自動更新的情況。)
與插件在運作時動态更新不同,伺服器系統無法在運作時動态更新,隻有在伺服器系統重新啟動的時候,才是自動更新的切入點。
(1)對于功能伺服器FS,可以采用持續/逐個更新的方式,即依次重新開機每個功能伺服器。這樣可以避免功能服務被中斷的情況發生。需要注意的是,隻有當目标FS上沒有功能請求時,才可重新開機該FS,否則,會導緻終端出現送出請求沒有響應的糟糕的使用者體驗。解決方案是:在FS重新開機之前,FS向對應的AS報告自己馬上将重新開機,這樣,AS不會再将請求分派到該FS上,一段時間後,本FS上就沒有功能請求了,于是可以順利重新開機了。
(2)對于IRAS與AS,則需要在重新開機前滿足本系統中沒有功能請求的條件,這可以通過一段時間不接受終端連接配接請求來做到。如果不能停止AS服務,則可以在更新本區域AS的時候,先啟用備用AS(可以通過端口映射在主AS和備用AS之間切換),當更新完成後,再切換回來。
上面已經提到,當伺服器重新開機的時候是系統更新的切入點,這個切入點一般在Main函數中,并且位于Application.Run之前。如下面示例代碼所示:
#region 系統更新
if(MainClass.AsConfig.UpdateEnabled)
{
DataCenterBase.Common.DataCenterHelper dataCenterHelper = (DataCenterBase.Common.DataCenterHelper)MainClass.SpringContext.GetObject("dataCenterHelper") ;
//如果有新版本
if(dataCenterHelper.GetAppServerNewVersion() > MainClass.Version)
{
string dir = System.IO.Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath) ;
//更新程式的路徑
string updateExePath = dir + "\\" + MainClass.AsConfig.UpdateExeFileName ;
//啟動更新程式、并退出Main
EnterpriseServerBase.Common.AdvancedFunction.StartApplication(updateExePath) ;
return ;
}
}
#endregion
需要自動更新的系統(比如上面的AS)中與更新相關的代碼大緻就這麼多,而本文我們重點要關注的是更新程式的實作。更新程式中核心接口是IAutoUpdator,位于ESFramework.Deploy命名空間中:
public interface IAutoUpdator
{
void Start() ;
void Cancel() ;
IUpdateAssistant UpdateAssistant{set ;}
IUiReporter UiReporter{set ;}
event CbSimple UpdateFinished ;
}
Start方法将啟動更新過程,當更新完成的時候,将觸發UpdateFinished事件。更新開始時,IAutoUpdator讀取本地配置檔案中中應用程式和各個dll及相關檔案的版本資訊,然後與擷取的最新版本資訊相比較,以決定要更新哪些exe或dll,要删除哪些dll,要新下載下傳哪些exe或dll。針對每個exe或dll(甚至是有更新需要的重要檔案),都有一個OneUpdate對象與之對應。
public class OneUpdate
public UpdatingType UpdateType = UpdatingType.Keep ;
public string URL ;
public string FilePath ;
public string FileName ;
public float NewVersion ;
/// <summary>
/// UpdatingType 更新類型
/// </summary>
public enum UpdatingType
Add ,Remove ,Update ,Keep //keep 表示不需更新
這與前文的插件更新是相同的。有人會問,為什麼插件更新和應用程式更新不做成一樣的元件,這樣可以更多的複用啊?那是因為它們更新的模式是不一樣的,插件是動态更新的,而應用程式本身隻能是靜态更新的(當然,即使你動态更新了這個應用程式中加載的插件)。
如果要順利的完成更新,有些必要的資訊需要擷取,比如最新版本的版本号,最新版本的伺服器系統exe及相關dll的下載下傳位址等等,這些是通過IUpdateAssistant接口提供的:
public interface IUpdateAssistant
IUpdateInformation[] GetUpdateInformation() ; //擷取最新版本檔案(exe、dll等)的下載下傳位址資訊
FileInfo[] GetFileInfoToUpdate() ; //擷取要更新檔案(exe、dll等)的目前版本
string GetFileDirectory() ;
// 通常操作本地配置檔案
void ReviseFileVersion(string fileName ,float newVer) ; //增加或修改
void RemoveFileVersion(string fileName) ;
public class FileInfo
public float Version ;
public interface IUpdateInformation
string FileName {get ;set ;}
string URL {get ;set ;}
float Version {get ;set ;}
string FileType {get ;set ;}
bool IsValid{get ;set ;}
不同的應用對IUpdateAssistant的實作是不同的。比如有的把最新版本的伺服器系統exe及相關dll存放在資料庫中,有的則可能放在某個Web上,以通過URL下載下傳擷取,等等。 有時新版本的應用程式可能需要删除舊版本中的某些不再需要的dll或其它輔助檔案,RemoveFileVersion用于這個目的。而當應用程式及相關dll更新完成後,就需要更改本地配置中的相應版本号,ReviseFileVersion提供了此功能。
IAutoUpdator通過IUiReporter接口将更新的進度資訊通知給UI,這樣使用者就對更新的程序就了然于胸了。
public interface IUiReporter
void Initialize(int minVal ,int MaxVal ,int val) ;
void Set(int val) ;
void ShowMessage(string msg) ;
當有重要事件發生(比如網絡斷開)而導緻更新失敗,IUpdateAssistant會通過IUiReporter的ShowMessage方法給出通知。借助于上述的各個輔助接口,實作IAutoUpdator就非常easy了,實作源碼參見SFramework.Deploy.AutoUpdator類。
在AutoUpdator的幫助下實作你自己的自動更新程式可以這樣做,首先建立一個新的WinForm項目,根據你應用的需要,實作上面列出的各個輔助接口,然後将這些實作裝配給AutoUpdator,就像這樣:
public Form1()
{
InitializeComponent();
this.autoUpdator = new AutoUpdator() ;
this.autoUpdator.UiReporter = this ;
this.autoUpdator.UpdateAssistant = new UpdateAssistant() ;
this.autoUpdator.UpdateFinished += new CbUpdate(autoUpdator_UpdateFinished);
}
然後在Load事件中啟動更新:
private void Form1_Load(object sender, System.EventArgs e)
{
this.autoUpdator.Start() ;
最後,當更新完成時,需要重新啟動新版本的應用程式:
private void autoUpdator_UpdateFinished()
MessageBox.Show("更新完成!") ;
string apppath = System.IO.Directory.GetParent(Application.ExecutablePath).ToString();
EnterpriseServerBase.Configure.XmlParser xmlParser = new EnterpriseServerBase.Configure.XmlParser(apppath + "\\" + "VersionInfo.xml");
//啟動新版本的應用程式
Process downprocess = new Process();
downprocess.StartInfo.FileName = string.Format("{0}\\{1}" , apppath ,xmlParser.GetConfigValue("HostInfo" ,"StartAppName")) ;
downprocess.Start();
this.Close() ;
目前的設計,主要支援從Url下載下傳最新版本的檔案(這可從IUpdateInformation接口的URL屬性看出),這也是最常見的方式。當然你可以将最新版本的檔案存放在資料庫中,這時就需要将IUpdateInformation接口定義修改一下即可适應。發揮你的創造力吧,歡迎和我交流你的想法!
感謝關注!