C/S架構的應用程序須要支持自動更新功能,當新版本程序發佈後,正在運行的客戶端能檢測到新版本的程序,通知用戶是否下載更新。工做以來參與過幾個自動更新模塊的設計與維護,撰文總結自動更新模塊設計與實現。html
1 版本比較。舊版本如何檢測到新版本,版本信息是程序集自描述的,仍是用單獨的文件保存。.NET程序集是自描述的,程序集包含如下幾種版本信息,每一個Assebmly包含三個Version
AssemblyFileVersion : 存儲在Win32資源中, CLR不關心這個版本號。
AssemblyInformationnalVersion :存儲在Win32資源中, CLR不關心這個版本號。
AssemblyVersion: 存儲在AssemblyDef manifest metadata table中,CLR會使用這個版本號。windows
標準版本號物理形式表示爲用句點隔開的四段數字,以下面的代碼示例所示。
<major version>.<minor version>.<build number>.<revision>
實際使用中,咱們通常只用到前面三段。即
<major version>.<minor version>.<build number> 服務器
版本比較舉例: 網絡
舊版本 2.4.1.2 架構
新版本 2.4.1.3 或 2.4.2.2 或2.5.1.2。 異步
2 程序下載。採用何種方式,從哪裏下載最新版本的程序。 優化
1) Http 協議。從IIS或Tomcat 等Web服務器中下載新版本的程序文件。 網站
2) Ftp協議。從Ftp服務器下載新版本的程序文件。 ui
3) 局域網共享。從內部局域網下載新版本的程序文件。 spa
下載過程當中應該支持斷點續傳,支持以壓縮文件的方式傳輸,下載完成後自動解壓縮,執行更新。還能夠參考Windows的BITS更新服務,BITS (後臺智能傳送服務) 是一個 Windows 組件,它能夠在前臺或後臺異步傳輸文件,爲保證其餘網絡應用程序得到響應而調整傳輸速度,並在從新啓動計算機或從新創建網絡鏈接以後自動恢復文件傳輸。
爲了達到傳輸過程當中速度最優化,能夠考慮調用第三方下載API,實現穿越局域網時,下載速度最快。
4) ClickOnce方式。將程序部署在IIS網站中,配置ClickOnce,參考文章 ClickOnce部署。
3 執行更新。若是更新程序是壓縮格式的zip/rar格式文件,可解壓縮後複製到應用程序目錄便可。若是更新程序是安裝格式的Installer文件,則須要先退出當前程序,啓動安裝程序包。
當前程序正在執行時,將更新程序覆蓋過來,會遇到文件被進程佔用的狀況,有如下三種解決方案:
1) 根據更新程序生成一個批處理命令,主要內容是將更新程序中的文件複製到當前程序所在文件夾。命令主要包含如下三個部分,退出當前程序,執行文件複製,啓動應用程序。
2) 應用程序啓動一個獨立的更新程序Update.EXE,由更新程序完成文件的複製和程序的啓動。
3) 調用Volume Shadow Copy Service,這個服務支持當文件正在被進程使用,仍能夠複製。
詳細參考如下網站信息 Volume Shadow Copy Service。
1) 文件包含版本信息,舉例EnterpriseSolution-5.3.0.0-20150401.zip,表示是5.3版本的,構建日期是2015年4月1日。在檢測更新文件時,須要遍歷同版本或是高版本的文件,取最新的那個文件。
2) 文件不包含版本信息,須要用獨立的描述文件表達版本信息。好比
<?xml version="1.0" encoding="utf-8" ?> <Content> <Project id="Enterprise.Sales.dll" Edition="1.2"> </Project> <Project id="Enterprise.Purchasing.dll" Edition="1.2"> </Project> <Project id="Enterprise.Inventory.dll" Edition="1.3"> </Project> <Project id="Enterprise.GeneralLedger.dll" Edition="1.5"> </Project> </Content>
經過這個描述文件,找到最新版本的文件,分批下載回來。對於服務器中存在多個版本的文件狀況,可用文件夾(1.2,1.5)的方式將各版本的程序文件放在各自的目錄中,經過上面的版本描述文件分別在各自的版本目錄中尋找文件。
檢測版本,發現新版本後啓動更新程序Update.EXE,退出當前程序。
string clientVersion = FileVersionInfo.GetVersionInfo(Assembly.GetEntryAssembly().Location).ProductVersion; string serverVersion = FileVersionInfo.GetVersionInfo("Main.exe", server)).ProductVersion; if (new Version(serverVersion).CompareTo(new Version(clientVersion)) > 0) { var process = new Process { StartInfo = new ProcessStartInfo { FileName = "Update.exe", Arguments = "LOCAL" } }; process.Start(); Environment.Exit(0); }
啓動外殼程序,在局域網(工做組)中經常使用來解決權限問題。
private static void Shell(string arguments) { Process process = new Process(); ProcessStartInfo processStartInfo = new ProcessStartInfo("cmd.exe", arguments); processStartInfo.WindowStyle = ProcessWindowStyle.Hidden; process.StartInfo = processStartInfo; process.Start(); }
經常使用在net use命令,舉例以下:
net use ipipc$ " " /user:" " 創建IPC空連接
net use ipipc$ "密碼" /user:"用戶名" 創建IPC非空連接
net use h: ipc$ "密碼" /user:"用戶名" 直接登錄後映射對方C:到本地爲H:
net use h: ipc$ 登錄後映射對方C:到本地爲H:
當準備檢測更新時,我須要檢測網絡是否通暢,須要用下面的方法:
1) 局域網模式下,用SystemInformation.Network可達到目的。
2) 要從外網下載程序,須要檢查外網是否連通,能夠採用PING一個IP地址的方式,要求這個IP地址或是域名很是穩定。
能夠調用C#的Ping類型完成目的,參考代碼:
Ping ping = new Ping(); PingOptions poptions = new PingOptions(); poptions.DontFragment = true;
也能夠調用COM接口InternetGetConnectedState,用於檢測網絡鏈接狀態。
[DllImport("wininet")] private extern static bool InternetGetConnectedState(out int connectionDescription, int reservedValue);
參考說明 InternetGetConnectedState function。
stackoverflow中有一篇講解判斷網絡鏈接的問答,地址是http://stackoverflow.com/questions/13457407/why-is-getisnetworkavailable-always-returning-true。
要檢測廣域網是否鏈接,須要使用InternetGetConnectedState()或WinINet API。