自動更新

C# 編寫自動更新程序javascript

如今但凡是一個程序都有相應的升級程序,若是你的程序沒有相應的升級程序,那麼你就須要留意了。你的用戶極可能丟失!!!網上關於自動升級的例子也有不少,前幾天一個朋友很苦惱的跟我說它的客戶在逐漸減小(據他所說,他都客戶由於他的程序升級很麻煩,因此不少人放棄了使用它的軟件),問我說怎麼辦?其實他也知道該怎麼辦?因此...朋友嘛!就給他作了一個自動升級程序。剛好今天CSDN上的一位老友也詢問這件事情,因此就把代碼共享你們了。
先個幾個圖:
 

 

主要原理(至關簡單):
升級程序必定要是一個單獨的exe,最好不要和你的程序綁到一塊兒(不然升級程序沒法啓動)。主程序退出----升級程序啓動----升級程序訪問你的網站的升級配置文件-----讀取配置文件裏面信息-----下載-----升級程序關閉----主程序啓動
主要代碼:
1.讀取配置文件:
private void GetUpdateInfo()  
{  
    //獲取服務器信息  
    WebClient client = new WebClient();  
    doc = new XmlDocument();  
    try 
    {  
        doc.Load(client.OpenRead(
            "http://192.168.3.43/update/update.xml"));  
 
        client = null;  
    }  
    catch 
    {  
        this.labHtml.Text =
            "沒法取得更新文件!程序升級失敗!";  
        return;  
    }  
    if (doc == null)  
        return;  
    //分析文件  
    XmlNode node;  
    //獲取文件列表  
    string RootPath =
        doc.SelectSingleNode("Product/FileRootPath").InnerText.Trim();  
    node = doc.SelectSingleNode("Product/FileList");  
    if (node != null)  
    {  
        foreach (XmlNode xn in node.ChildNodes)  
        {  
            this.listView1.Items.Add(
                new ListViewItem(new string[]  
                {  
                     xn.Attributes["Name"].Value.ToString(),
                     new WebFileInfo(RootPath+xn.Attributes["Name"]
                        .Value.ToString()).GetFileSize().ToString(),  
                    "---" 
                }));  
        }  
    }  
}
 
private void GetUpdateInfo()
{
    //獲取服務器信息
    WebClient client = new WebClient();
    doc = new XmlDocument();
    try
    {
        doc.Load(client.OpenRead(
            "http://192.168.3.43/update/update.xml"));
       
        client = null;
    }
    catch
    {
        this.labHtml.Text =
            "沒法取得更新文件!程序升級失敗!";
        return;
    }
    if (doc == null)
        return;
    //分析文件
    XmlNode node;
    //獲取文件列表
    string RootPath =
        doc.SelectSingleNode("Product/FileRootPath").InnerText.Trim();
    node = doc.SelectSingleNode("Product/FileList");
    if (node != null)
    {
        foreach (XmlNode xn in node.ChildNodes)
        {
            this.listView1.Items.Add(
                new ListViewItem(new string[]
                {
                     xn.Attributes["Name"].Value.ToString(),
                     new WebFileInfo(RootPath+
                        xn.Attributes["Name"].Value.ToString()).
                        GetFileSize().ToString(),
                    "---"
                }));
        }
    }
}
2.文件下載:
/// <summary>  
/// 下載文件  
/// </summary>  
public void Download()  
{  
    FileStream fs =
        new FileStream( this.strFile,FileMode.Create,
        FileAccess.Write,FileShare.ReadWrite ); 
 
    try 
    {  
        this.objWebRequest =
            (HttpWebRequest)WebRequest.Create( this.strUrl );  
        this.objWebRequest.AllowAutoRedirect = true;  
        long nCount = 0;  
        byte[] buffer = new byte[ 4096 ];   //4KB  
        int nRecv = 0;  //接收到的字節數  
 
        this.objWebResponse =
            (HttpWebResponse)this.objWebRequest.GetResponse();  
        Stream recvStream = this.objWebResponse.GetResponseStream();  
        long nMaxLength = (int)this.objWebResponse.ContentLength;
 
        if( this.bCheckFileSize && nMaxLength != this.nFileSize )  
        {  
            throw new Exception(
                string.Format( "文件\"{0}\"被損壞,沒法下載!",
                Path.GetFileName( this.strFile ) ) );  
        }  
        if( this.DownloadFileStart != null )  
            this.DownloadFileStart(
                new DownloadFileStartEventArgs( (int)nMaxLength ) ); 
 
        while( true )  
        {  
            nRecv = recvStream.Read( buffer,0,buffer.Length );  
            if( nRecv == 0 )  
                break;  
            fs.Write( buffer,0,nRecv );  
            nCount += nRecv;  
            //引起下載塊完成事件  
            if( this.DownloadFileBlock != null )  
                this.DownloadFileBlock(
                    new DownloadFileEventArgs( (int)nMaxLength,
                    (int)nCount ) );  
        }  
 
        recvStream.Close();   
        //引起下載完成事件  
        if( this.DownloadFileComplete != null )  
            this.DownloadFileComplete( this,EventArgs.Empty );  
    }  
    finally 
    {  
        fs.Close();  
    }  
} 
/// <summary>
/// 下載文件
/// </summary>
public void Download()
{
    FileStream fs =
        new FileStream( this.strFile,FileMode.Create,
        FileAccess.Write,FileShare.ReadWrite );
    try
    {
        this.objWebRequest =
            (HttpWebRequest)WebRequest.Create( this.strUrl );
        this.objWebRequest.AllowAutoRedirect = true;
        //    int nOffset = 0;
        long nCount = 0;
        byte[] buffer = new byte[ 4096 ]; //4KB
        int nRecv = 0; //接收到的字節數
        this.objWebResponse =
            (HttpWebResponse)this.objWebRequest.GetResponse();
        Stream recvStream = this.objWebResponse.GetResponseStream();
        long nMaxLength = (int)this.objWebResponse.ContentLength;
 
        if( this.bCheckFileSize && nMaxLength != this.nFileSize )
        {
            throw new Exception(
                string.Format( "文件\"{0}\"被損壞,沒法下載!",
                Path.GetFileName( this.strFile ) ) );
        }
        if( this.DownloadFileStart != null )
            this.DownloadFileStart(
                new DownloadFileStartEventArgs( (int)nMaxLength ) );
 
        while( true )
        {
            nRecv = recvStream.Read( buffer,0,buffer.Length );
            if( nRecv == 0 )
            break;
            fs.Write( buffer,0,nRecv );
            nCount += nRecv;
            //引起下載塊完成事件
            if( this.DownloadFileBlock != null )
                this.DownloadFileBlock(
                    new DownloadFileEventArgs( (int)nMaxLength,
                    (int)nCount ) );
        }
        recvStream.Close();
        //引起下載完成事件
        if( this.DownloadFileComplete != null )
            this.DownloadFileComplete( this,EventArgs.Empty );
    }
    finally
    {
        fs.Close();
    }
}

 
歡迎轉載,轉載請註明出處:)
 
View Code

C# 使用WebService更新客戶端軟件前端

先實現 WEB端的開發,主要考慮使用WEBService技術,提供遠程服務的調用函數 。因爲項目緣由,要實施的客戶離做者太遠,考慮提供軟件的在線升級功能.咱們C# WebService來實現。先講下思路.
思路:
    先實現 WEB端的開發,主要考慮使用C# WebService技術,提供遠程服務的調用函數,返回一個文件的字節內容,而後寫一個升級程序客戶端,分發給客戶使用的機器中,(能夠隨客戶的軟件一塊兒安裝).該客戶端程序主要鏈接webserivce,而後將文件保存到本地機(客戶的機器)中.就能夠實現!
實現的細節:
   要考慮提供給客戶軟件版本問題,低版本的升級,最新版本的就不用升級.還要考慮用戶名與密碼在WEB端的認證!
使用技術:
     ASP.Net WebService開發,客戶端的異步調用WebService方法.數據庫技術!
開始實現:
1. 1.創建數據庫,使用SQLSERVER2000  
2. 1)軟件項目表:softlist(softid, softname,   
3. resume, loginname, loginpwd)  
4. softid:編號  
5. softname:軟件名稱  
6. resume:介紹  
7. loginname:客戶登陸名  
8. loginpwd:密碼  
9.  
10.  
11. 2)各個軟件的版本表 SoftListVersion(softid, subid,   
12. version, UpdatePath, olefile)  
13. softid:主表的軟件編號  
14. subid:各版本數據編號  
15. version:軟件版本  
16. filename:升級文件名  
17. olefile:升級文件的二進制內容,是image類型,  
18. (我主要存放MSI的安裝包文件類型,可使用C#作此類安裝包文件)  
19.  
20. 3)創建一個視圖,chkVersion,用於檢查版本號  
21. SELECT dbo.SoftListVersion.subid, dbo.softlist.  
22. softname, dbo.SoftListVersion.version  
23. FROM dbo.softlist INNER JOIN 
24. dbo.SoftListVersion ON dbo.softlist.softid =   
25. dbo.SoftListVersion.softid  
26.  
27. 4)再創建一個視圖,vOleFile,用於下載文件  
28. SELECT dbo.SoftListVersion.subid, dbo.softlist.  
29. softname, dbo.SoftListVersion.filename,  
30. dbo.SoftListVersion.olefile, dbo.SoftListVersion.version  
31. FROM dbo.softlist INNER JOIN 
32. dbo.SoftListVersion ON dbo.softlist.softid =   
33. dbo.SoftListVersion.softid  
34.  
35. 2.寫一個WEBSERVICE  
36. 1)啓動VS.Net2003,創建一個叫babyWebSvc的項目,  
37. 項目類型爲(ASP.Net WEB服務)  
38. 2)添加一個SoftUpdate.asmx的WEB服務  
39.  
40. 3)添加一個方法SearchVersion  
41.  
42. [WebMethod(Description=43. 返回當前軟件升級包的最高版本」)]  
44. public string SearchVersion(string softname)  
45. {  
46. string sVersion = 」」;  
47. webmod.dbConnStart(); //  
48. (鏈接)做者本身的鏈接數據庫類,用戶本身完成數據庫鏈接  
49. string strSQL = 」select MAX(version) as   
50. MaxVerID from chkVersion where softname = @softname」;  
51. SqlCommand sqlCmd = new SqlCommand(strSQL,webmod.sqlConn);  
52. sqlCmd.CommandTimeout = 0;  
53. sqlCmd.Parameters.Add(」@softname」,SqlDbType.VarChar).  
54. Value = softname;  
55. SqlDataReader sqlRd = sqlCmd.ExecuteReader();  
56. if(sqlRd.HasRows)  
57. {  
58. sqlRd.Read();  
59. sVersion = Convert.ToString(sqlRd[」MaxVerID」]);  
60. }  
61. sqlRd.Close();  
62.  
63. webmod.dbConnEnd(); //(斷開鏈接)做者本身的鏈接數據庫類,  
64. 用戶本身完成數據庫鏈接  
65.  
66. return sVersion;  
67. }  
68.  
69. 4)添加下載文件內容的方法DownloadSoft  
70.  
71. [WebMethod(Description=」返回須要下載的文件字節」)]  
72. public byte[] DownloadSoft(string UserName,string PassWord,  
73. string SoftDnldName,string SoftHeightVersion)  
74. {  
75. //(鏈接)做者本身的鏈接數據庫類,用戶本身完成數據庫鏈接  
76. webmod.dbConnStart();  
77.  
78. //檢查用戶合法性  
79. bool bMember = CheckAuth(UserName,PassWord);  
80. //該WebService內的一個檢查用戶合法性的函數,用戶能夠本身完成  
81. if(!bMember)  
82. {  
83. webmod.dbConnEnd();  
84. return null;  
85. }  
86. byte[] b = null;  
87.  
88. //咱們取出指定軟件名稱的最高版本的升級包  
89. string strSQL = 」select olefile from vOleFile where   
90. (filename=@softname) and version=@ver」;  
91. SqlCommand sqlCmd = new SqlCommand(strSQL,webmod.sqlConn);  
92. sqlCmd.CommandTimeout = 0;  
93. sqlCmd.Parameters.Add(」@softname」,SqlDbType.VarChar).  
94. Value = SoftDnldName;  
95. sqlCmd.Parameters.Add(」@ver」, SqlDbType.VarChar).  
96. Value = SoftHeightVersion;  
97. SqlDataReader sqlRd = sqlCmd.ExecuteReader();  
98. if(sqlRd.HasRows)  
99. {  
100. sqlRd.Read();  
101. b = (byte[])sqlRd[」olefile」];//文件的字節內容  
102. }  
103. sqlRd.Close();  
104.  
105. //(斷開鏈接)做者本身的鏈接數據庫類,用戶本身完成數據庫鏈接  
106. webmod.dbConnEnd();  
107. return b;  
108. }  
    3.WEB服務的方法完成後,你本身能夠啓動,測試,咱們如今來寫客戶端的升級程序,假定你在開發時的WEBSERVICE的URL爲:http://localhost/babywebsvc/SoftUpdate.asmx,注意這個URL,咱們是要在客戶端引用的
    4.啓動VS.Net2003,創建一個C#的Windows項目,在默認的FORM上添加一個按鈕,
    5.添加一個新的文件類型(應用程序配置文件)App.config
    App.Config文件的內容
1. 〈?xml version=」1.0」 encoding=」utf-8」?2. 〈configuration〉  
3. 〈appSettings〉  
4. 〈add key=」user」 value=」test」/5. 〈add key=」pwd」 value=」test」/6. 〈add key=」babyRecordSoftName」 value=7. TEST.EXE」/〉〈!--記錄在遠程的數據庫中的軟件名稱--8. 〈add key=」Version」 value=」1.0」/9. 〈/appSettings〉  
10. 〈/configuration〉 
    6.咱們在Form啓動的LOAD事件中,添加以下代碼
1. private void Form1_Load(object sender,   
2. System.EventArgs e)  
3. {  
4. //讀出版本號,該版本號是在AssemblyInfo.cs  
5. 中由系統自己設置的,[assembly: AssemblyVersion(」1.0」)]  
6. //之後要更改,能夠改此處的AssemblyInfo.cs中的版本號,  
7. 例:[assembly: AssemblyVersion(」1.1」)]  
8. //咱們的WEBSERVICE中須要這個數據作爲參數  
9. string sVersion = Application.ProductVersion;  
10.  
11. //寫到App.Cofing文件中,每次調用WEBSERVICE方法時,  
12. 從App.Cofing中讀取版本,你也能夠直接使用Application.  
13. ProductVersion,我是爲了統一管理,所有從config中讀取  
14. this.SaveAppConfig(」Version」,sVersion);  
15. }  
16.  
17. //SaveAppConfig函數的內容  
18. public static void SaveAppConfig  
19. (string AppKey,string AppValue)  
20. {  
21. XmlDocument xDoc = new XmlDocument();  
22. xDoc.Load(Application.ExecutablePath + 」.config」);  
23.  
24. XmlNode xNode;  
25. XmlElement xElem1;  
26. XmlElement xElem2;  
27.  
28. xNode = xDoc.SelectSingleNode(」//appSettings」);  
29.  
30. xElem1 = (XmlElement)xNode.SelectSingleNode(  
31. 」//add[@key=」 + AppKey + 」]」);  
32. if ( xElem1 != null ) xElem1.SetAttribute(」  
33. value」,AppValue);  
34. else 
35. {  
36. xElem2 = xDoc.CreateElement(」add」);  
37. xElem2.SetAttribute(」key」,AppKey);  
38. xElem2.SetAttribute(」value」,AppValue);  
39. xNode.AppendChild(xElem2);  
40. }  
41. xDoc.Save(Application.ExecutablePath + 」.config」);  
42. }  
    7.主要部分,開始調用webservice的方法!
    準備工做:1)添加一個WEB引用,(先點菜單」項目」-」添加WEB引用」),
    在彈出中輸入url的路徑:http://localhost/babywebsvc/SoftUpdate.asmx
    2)假定你在開發時的WEBSERVICE的URL:http://localhost/babywebsvc/SoftUpdate.asmx
    3)填入WEB引用名:AutoUpdateWebSvc
    4)點下按紐完成WEB引用的添加
    8.在你的Button1_click事件中添加以下CODE,主要使用異步調用
1. private string svcUser = 」」;  
2. private string svcPwd = 」」;  
3. private string svcSoftName = 」」;  
4. private string svcCurrVersion = 」」;  
5. private string svcDnldFileName = 」Test.MSI」;  
6. //下載下來的文件名,  
7. private byte[] fbyte = null;   
8. //下載後的升級文件的內容  
9. private void Button1_Click(object sender,   
10. System.EventArgs e)  
11. {  
12. //讀取App.config文件中的配置信息  
13. svcUser = System.Configuration.  
14. ConfigurationSettings.AppSettings[」user」];   
15. //須要人證的用戶名  
16. svcPwd = System.Configuration.  
17. ConfigurationSettings.AppSettings[」pwd」];  
18.  //認證密碼  
19. svcSoftName = System.Configuration.  
20. ConfigurationSettings.AppSettings  
21. [」babyRecordSoftName」];//軟件名稱  
22. svcCurrVersion = System.Configuration.  
23. ConfigurationSettings.AppSettings[」Version」];  
24. //當前版本號  
25.  
26. try  
27. {  
28. AutoUpdateWebSvc.SoftUpdate aSvc =   
29. new AutoUpdateWebSvc.SoftUpdate();  
30.  
31. //此處能夠改爲本身實際應用時的URL,  
32. 無論WEB引用是動態仍是靜態,調用都會指向該URL  
33. aSvc.Url =34. http://localhost/babyWebSvc/SoftUpdate.asmx」;  
35.  
36. if(Button1.Text.Trim() == 」檢 查」)  
37. {  
38. //檢查最新版本  
39. System.AsyncCallback cb = new AsyncCallback  
40. (SearchVersionCallBack);//異步回調方法,  
41. 並檢查是否有高版本的升級軟件存在  
42. aSvc.BeginSearchVersion(svcSoftName,cb,aSvc);  
43. }  
44. else if(Button1.Text.Trim() == 」升 級」)  
45. {  
46. //開始調用下載服務  
47. InvokeDownload(); //函數體見下面的CODE  
48. }  
49.  
50. }  
51. catch(Exception ex)  
52. {  
53. MessageBox.Show(ex.Message);  
54. }  
55. }  
56.  
57.  
58. //檢查最新版本的異步回調方法  
59. private void SearchVersionCallBack(System.  
60. IAsyncResult ar)  
61. {  
62. if(ar==null)return;  
63. if(ar.IsCompleted)  
64. {  
65. try  
66. {  
67. AutoUpdateWebSvc.SoftUpdate aSvc =   
68. (AutoUpdateWebSvc.SoftUpdate)ar.AsyncState;  
69. string sVersion = aSvc.EndSearchVersion(ar);  
70. aSvc.Dispose();  
71.  
72.  
73. if(svcCurrVersion.Trim() == sVersion.Trim())  
74. MessageBox.Show」你的軟件當前版本已是最新的了,  
75. 無需進行升級...」);  
76. else if((string.Compare(svcCurrVersion.Trim(),  
77. sVersion.Trim()))==-1)  
78. {  
79.  
80. MessageBox.Show(」你的軟件當前版本比較低,  
81. 能夠進行升級...」);  
82. Button1.Text = 」升 級」;  
83. }  
84.  
85. }  
86. catch(Exception ex)  
87. {  
88. MessageBox.Show(ex.Message);  
89. }  
90. }  
91. }  
92.  
93. //調用遠程的WEB服務,開始下載  
94. private void InvokeDownload()  
95. {  
96. try  
97. {  
98. AutoUpdateWebSvc.SoftUpdate aSvc =   
99. new AutoUpdateWebSvc.SoftUpdate();  
100. //此處能夠改爲本身實際應用時的URL,  
101. 無論WEB引用是動態仍是靜態,調用都會指向該URL  
102. aSvc.Url =103. http://localhost/babyWebSvc/SoftUpdate.asmx」;  
104.  
105. //開始下載  
106. System.AsyncCallback cb =   
107. new AsyncCallback(DownloadSoftCallBack);  
108. //異步回調方法,保存文件  
109. aSvc.BeginDownloadSoft(svcUser,svcPwd,  
110. svcDnldFileName,lblVersion.Text.Trim(),cb,aSvc);  
111.  
112. }  
113. catch(Exception ex)  
114. {  
115. MessageBox.Show(ex.Message);  
116. }  
117. }  
118.  
119. //下載方法執行完成後,異步回調方法  
120. private void DownloadSoftCallBack(System.  
121. IAsyncResult ar)  
122. {  
123. if(ar==null)  
124. {  
125. MessageBox.Show(」升級過程當中出現錯誤,  
126. 不能進行升級,請稍後再試...」);  
127. return;  
128. }  
129. if(ar.IsCompleted)  
130. {  
131. try  
132. {  
133. AutoUpdateWebSvc.SoftUpdate aSvc =   
134. (AutoUpdateWebSvc.SoftUpdate)ar.AsyncState;  
135. fbyte = aSvc.EndDownloadSoft(ar);  
136. aSvc.Dispose();  
137.  
138. //使用線程,保存文件  
139. Thread th = new Thread(new ThreadStart(Save2Disk));  
140. th.Start();  
141.  
142. }  
143. catch(Exception ex)  
144. {  
145. MessageBox.Show(」升級過程當中出現錯誤,」+ex.Message);  
146. }  
147. }  
148. }  
149.  
150.  
151. //將下載下來的字節數組保存成文件  
152. private void Save2Disk()  
153. {  
154. try  
155. {  
156. FileInfo finfo = new FileInfo  
157. (Application.ExecutablePath+svcDnldFileName);  
158. if(finfo.Exists)finfo.Delete();//文件存在就刪除它  
159. Stream stream = finfo.OpenWrite();  
160.  
161. prosBar.Maximum = fbyte.Length;//prosBar是一個進度條  
162. prosBar.Minimum = 0;  
163. prosBar.Step = 1;  
164. int i=0;  
165. foreach(byte b in fbyte)  
166. {  
167. stream.WriteByte(b);  
168. prosBar.Value += 1;  
169. }  
170. stream.Flush();  
171. stream.Close();  
172.  
173. DialogResult dr = MessageBox.Show  
174. (」下載完成,是否如今就安裝升級程序...」,」  
175. 提示信息」,MessageBoxButtons.OKCancel,  
176. MessageBoxIcon.Information,MessageBoxDefaultButton.  
177. Button1);  
178. if(dr == DialogResult.OK)  
179. {  
180. ExecSetup();//啓動下載下來的安裝程序,用戶能夠本身完成  
181. }  
182. }  
183. catch(Exception ex)  
184. {  
185. MessageBox.Show(」升級過程當中出現錯誤,」+ex.Message);  
186. }  
187. uiButton2.Enabled = true;  
188. }  
    9:總結,客戶端調用,是從,點擊Buttton1開始,搜索版本號,SearchVersion,當找到高版本升級包時,開始執行下載的方法DownloadSoft,而後保存到本地Save2Disk.無論客戶端的調用是同步仍是異步,WEBService的方法都是同樣寫的,只不過同步調用,是直接使用WEBService中的方法名稱,異步調用則會由系統自動生成BeginXXX()與EndXXX()的方法名稱,提供給你使用。
    通過上面的步驟,就基本實現了C# WebService更新客戶端軟件。
 
View Code

C#實現程序的版本自動升級更新java

咱們作了程序,難免會有版本升級,這就須要程序有自動版本升級的功能。
那麼看看我是如何實現程序自動更新的。
直接上代碼:
  1 using System;   

  2 using System.Collections.Generic;   

  3 using System.Text;   

  4 using System.Reflection;   

  5 using System.IO;   

  6 using System.Net;   

  7 using System.Xml;   

  8   

  9 namespace Update   

 10 {   

 11     /// <summary>   

 12     /// 更新完成觸發的事件   

 13     /// </summary>   

 14     public delegate void UpdateState();   

 15     /// <summary>   

 16     /// 程序更新   

 17     /// </summary>   

 18     public class SoftUpdate   

 19     {   

 20   

 21         private string download;   

 22         private const string updateUrl = "http://www.csdn.net/update.xml";//升級配置的XML文件地址  

 23  

 24         #region 構造函數   

 25         public SoftUpdate() { }   

 26   

 27         /// <summary>   

 28         /// 程序更新   

 29         /// </summary>   

 30         /// <param name="file">要更新的文件</param>   

 31         public SoftUpdate(string file,string softName) {   

 32             this.LoadFile = file;   

 33             this.SoftName = softName;   

 34         }   

 35         #endregion  

 36  

 37         #region 屬性   

 38         private string loadFile;   

 39         private string newVerson;   

 40         private string softName;   

 41         private bool isUpdate;   

 42   

 43         /// <summary>   

 44         /// 或取是否須要更新   

 45         /// </summary>   

 46         public bool IsUpdate   

 47         {   

 48             get    

 49             {   

 50                 checkUpdate();   

 51                 return isUpdate;    

 52             }   

 53         }   

 54   

 55         /// <summary>   

 56         /// 要檢查更新的文件   

 57         /// </summary>   

 58         public string LoadFile   

 59         {   

 60             get { return loadFile; }   

 61             set { loadFile = value; }   

 62         }   

 63   

 64         /// <summary>   

 65         /// 程序集新版本   

 66         /// </summary>   

 67         public string NewVerson   

 68         {   

 69             get { return newVerson; }   

 70         }   

 71   

 72         /// <summary>   

 73         /// 升級的名稱   

 74         /// </summary>   

 75         public string SoftName   

 76         {   

 77             get { return softName; }   

 78             set { softName = value; }   

 79         }  

 80  

 81         #endregion   

 82   

 83         /// <summary>   

 84         /// 更新完成時觸發的事件   

 85         /// </summary>   

 86         public event UpdateState UpdateFinish;   

 87         private void isFinish() {   

 88             if(UpdateFinish != null)   

 89                 UpdateFinish();   

 90         }   

 91   

 92         /// <summary>   

 93         /// 下載更新   

 94         /// </summary>   

 95         public void Update()   

 96         {   

 97             try  

 98             {   

 99                 if (!isUpdate)   

100                     return;   

101                 WebClient wc = new WebClient();   

102                 string filename = "";   

103                 string exten = download.Substring(download.LastIndexOf("."));   

104                 if (loadFile.IndexOf(@"\") == -1)   

105                     filename = "Update_" + Path.GetFileNameWithoutExtension(loadFile) + exten;   

106                 else  

107                     filename = Path.GetDirectoryName(loadFile) + "\\Update_" + Path.GetFileNameWithoutExtension(loadFile) + exten;   

108                 wc.DownloadFile(download, filename);   

109                 wc.Dispose();   

110                 isFinish();   

111             }   

112             catch  

113             {   

114                 throw new Exception("更新出現錯誤,網絡鏈接失敗!");   

115             }   

116         }   

117   

118         /// <summary>   

119         /// 檢查是否須要更新   

120         /// </summary>   

121         public void checkUpdate()    

122         {   

123             try {   

124                 WebClient wc = new WebClient();   

125                 Stream stream = wc.OpenRead(updateUrl);   

126                 XmlDocument xmlDoc = new XmlDocument();   

127                 xmlDoc.Load(stream);   

128                 XmlNode list = xmlDoc.SelectSingleNode("Update");   

129                 foreach(XmlNode node in list) {   

130                     if(node.Name == "Soft" && node.Attributes["Name"].Value.ToLower() == SoftName.ToLower()) {   

131                         foreach(XmlNode xml in node) {   

132                             if(xml.Name == "Verson")   

133                                 newVerson = xml.InnerText;   

134                             else  

135                                 download = xml.InnerText;   

136                         }   

137                     }   

138                 }   

139   

140                 Version ver = new Version(newVerson);   

141                 Version verson = Assembly.LoadFrom(loadFile).GetName().Version;   

142                 int tm = verson.CompareTo(ver);   

143   

144                 if(tm >= 0)   

145                     isUpdate = false;   

146                 else  

147                     isUpdate = true;   

148             }   

149             catch(Exception ex) {   

150                               throw new Exception("更新出現錯誤,請確認網絡鏈接無誤後重試!");   

151             }   

152         }   

153   

154         /// <summary>   

155         /// 獲取要更新的文件   

156         /// </summary>   

157         /// <returns></returns>   

158         public override string ToString()   

159         {   

160             return this.loadFile;   

161         }   

162     }   

163 }  
把代碼編譯爲一個類庫文件,經過程序引用就OK啦。
傳入的參數已經有註釋了。
下面是更新的XML文件類容,傳到空間上面就能夠了,獲得XML文件的地址。
1 <?xml version="1.0" encoding="utf-8" ?>    

2 <Update>  

3    <Soft Name="BlogWriter">  

4      <Verson>1.0.1.2</Verson>    

5      <DownLoad>http://www.csdn.net/BlogWrite.rar</DownLoad>    

6   </Soft>  

7 </Update>  
程序更新調用方法:
 1、先引用上面的DLL。
 2、調用方法代碼 以下:
 1 using System;   

 2 using System.Collections.Generic;   

 3 using System.ComponentModel;   

 4 using System.Data;   

 5 using System.Drawing;   

 6 using System.Text;   

 7 using System.Windows.Forms;   

 8 using System.IO;   

 9 using System.Threading;   

10 using System.Net;   

11 using System.Xml;   

12 using Update;   

13   

14 namespace UpdateTest   

15 {   

16     public partial class Form1 : Form   

17     {   

18         public Form1()   

19         {   

20             InitializeComponent();   

21             checkUpdate();   

22         }   

23   

24         public void checkUpdate()   

25         {   

26             SoftUpdate app = new SoftUpdate(Application.ExecutablePath, "BlogWriter");   

27             app.UpdateFinish += new UpdateState(app_UpdateFinish);   

28             try  

29             {   

30                 if (app.IsUpdate && MessageBox.Show("檢查到新版本,是否更新?", "Update", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)   

31                 {   

32   

33                     Thread update = new Thread(new ThreadStart(app.Update));   

34                     update.Start();   

35                 }   

36             }   

37             catch (Exception ex)   

38             {   

39                 MessageBox.Show(ex.Message);   

40             }   

41         }   

42   

43         void app_UpdateFinish() {   

44                 MessageBox.Show("更新完成,請從新啓動程序!", "Update", MessageBoxButtons.OK, MessageBoxIcon.Information);   

45         }   

46   

47     }   

48 }  
 
View Code

C#使用FTP實現客戶端程序自動更新node

最近作的一個項目中須要用到客戶端自動更新功能,最初的想法是利用ClickOnce技術來完成,但在實踐中發現根本行不能,緣由以下:
1)項目應用到了DevExpress控件包,用ClickOnce發佈的自動更新程序,客戶在安裝時報在GAC中找不到控件dll的錯。
2)ClickOnce安裝沒法實現根據用戶安裝時錄入的參數(好比數據庫服務器名、數據庫用戶名和密碼等)來動態修改配置文件的功能。
3)最後一下其實不重要了,就是ClickOnce沒法實現用戶自定義安裝文件夾。
  最後決定放棄使用ClickOnce,使用ftp方式進行,實現思路以下:用戶啓動程序時,先運行update.exe,該文件會自動比較本地配置文件和ftp服務器上配置文件的異同,會自動下載上次更新後變化的文件以及新加入的文件。(由於都是基本配置文件,因此開發了一個配置文件生成工具,用戶只須要選擇根目錄後,就會自動生成配置文件。)文件下載結束後,再啓動實際的客戶端程序。
  程序的主要代碼如:
   


  1

using System;
  2

using System.Collections.Generic;
  3

using System.Diagnostics;
  4

using System.IO;
  5

using System.Net;
  6

using System.Threading;
  7

using System.Windows.Forms;
  8


  9

namespace Update
 10

{
 11

    /// <summary>
 12

    /// Description: 
 13

    /// Author: ZhangRongHua
 14

    /// Create DateTime: 2009-6-21 12:25
 15

    /// UpdateHistory:      
 16

    /// </summary>
 17

    public partial class frmUpdate : Form
 18

    {
 19

        #region Fields
 20


 21

        private const string CONFIGFILE = "update.xml";
 22

        private const string UPDATEDIR = "PMS";
 23

        private string appPath = Application.StartupPath;
 24

        private List<ErrorInfo> errorList = new List<ErrorInfo>();
 25

        private string locFile = String.Concat(Application.StartupPath, "\\", CONFIGFILE);
 26

        private string tmpUpdateFile = "TmpUpdate.xml";
 27

        private List<string> updateList;
 28

        private string updateTmpPath = string.Concat(Path.GetTempPath(), "\\", UPDATEDIR);   
 29

        private string url = String.Empty;
 30


 31

        private FTP ftp = null;
 32


 33

        #endregion
 34


 35

        #region Delegates
 36


 37

        public delegate void AsycDownLoadFile(string srcFile, string destFile, int i);
 38


 39

        public delegate void ExecuteUpdateFiles(string srcPath, string destPath);
 40


 41

        public delegate void UpdateComplete();
 42


 43

        public delegate void UpdateUI(int i, string message);
 44


 45

        #endregion
 46


 47

        public event UpdateComplete OnUpdateComplete;
 48


 49

        #region Constructor
 50


 51

        public frmUpdate()
 52

        {
 53

            InitializeComponent();
 54

            OnUpdateComplete += new UpdateComplete(frmUpdate_OnUpdateComplete);
 55

        }
 56


 57

        #endregion
 58


 59

        #region Event Handler
 60


 61

        private void frmUpdate_Load(object sender, EventArgs e)
 62

        {
 63

           if(Directory.Exists(updateTmpPath))
 64

           {
 65

               Directory.Delete(updateTmpPath, true);
 66

           }
 67

         
 68

            // 若是有主程序啓動,則關閉
 69

            Process[] ps = Process.GetProcesses();
 70

            foreach (Process p in ps)
 71

            {
 72

                //MessageBox.Show(p.ProcessName);
 73

                if (p.ProcessName.ToLower() == "wat.pms.winform")
 74

                {
 75

                    p.Kill();
 76

                    break;
 77

                }
 78

            }
 79


 80

            GetUpdateFiles();
 81

        }
 82


 83

        private void frmUpdate_OnUpdateComplete()
 84

        {
 85

            ExecuteUpdateFiles dExecuteUpdateFiles = new ExecuteUpdateFiles(ExecuteUpdate);
 86

            Invoke(dExecuteUpdateFiles, new object[] {updateTmpPath, appPath});
 87

        }
 88


 89

        private void frmUpdate_Shown(object sender, EventArgs e)
 90

        {
 91

            Thread updateThread = new Thread(new ThreadStart(DownLoadUpdateFiles));
 92

            updateThread.SetApartmentState(ApartmentState.STA);
 93

            updateThread.IsBackground = true;
 94

            Thread.Sleep(500);
 95

            updateThread.Start();
 96


 97

  
 98

         }
 99


100

        #endregion
101


102

        #region Private Methods
103


104

         /// <summary>
105

         /// 將目標文件替換爲本地文件
106

         /// <remark> 
107

         /// Author:ZhangRongHua 
108

         /// Create DateTime: 2009-6-21 10:28
109

         /// Update History:     
110

         ///  </remark>
111

         /// </summary>
112

         /// <param name="srcFile">The SRC file.</param>
113

         /// <param name="destFile">The dest file.</param>
114

        private void DownLoadFile(string srcFile, string destFile)
115

        {
116

            if(ftp == null )
117

            {
118

                ftp = new FTP(Updater.URL, "", Updater.User, Updater.Password);
119

            }
120


121

           
122


123

            if(!ftp.Connected)
124

            {
125

                MessageBox.Show("沒法鏈接遠程服務器,沒法更新程序", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
126

                Process.Start(Updater.MainProgram);
127

                Close();
128

                
129

            }
130


131

            // 獲得服務器端的配置文件
132

             ftp.Get(srcFile, updateTmpPath, destFile);
133


134

          
135

 
136

        }
137


138

        /// <summary>
139

        /// 獲得須要更新的文件清單
140

        /// <remark> 
141

        /// Author:ZhangRongHua 
142

        /// Create DateTime: 2009-6-21 10:29
143

        /// Update History:     
144

        ///  </remark>
145

        /// </summary>
146

        private void GetUpdateFiles()
147

        {
148

            Updater.GetBaseInfo(locFile);
149

            url = Updater.URL;
150

            string svrFile = String.Concat(url, CONFIGFILE);
151


152

            if (String.IsNullOrEmpty(svrFile))
153

            {
154

                BroadCastOnUpdateComplete();
155

                return;
156

            }
157


158

            Directory.CreateDirectory(updateTmpPath);
159

            try
160

            {
161

                DownLoadFile(CONFIGFILE, tmpUpdateFile);
162

            }
163

            catch (Exception ex)
164

            {
165

                MessageBox.Show("沒法鏈接遠程服務器,沒法更新程序", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
166

                Process.Start(Updater.MainProgram);
167

                Close();
168

            }
169


170

            updateList = Updater.GetUpdateFileList(locFile, tmpUpdateFile);
171

            if (updateList == null || updateList.Count < 1)
172

            {
173

                BroadCastOnUpdateComplete();
174

                return;
175

            }
176


177

            pbUpdate.Maximum = updateList.Count;
178

            pbUpdate.Minimum = 0;
179

            lblInfo.Text = String.Concat(updateList.Count, "個文件須要更新!");
180

            lblInfo.BringToFront();
181

            lblState.BringToFront();
182

            lblInfo.Update();
183


184

            pbUpdate.Maximum = updateList.Count;
185

            pbUpdate.Minimum = 0;
186


187

            for (int i = 0; i < updateList.Count; i++)
188

            {
189

                string file = updateList[i];
190

                ListViewItem lvItem = new ListViewItem();
191

                lvItem.Text = file;
192

                lvItem.SubItems.Add(Updater.MainProgramVersion);
193

                lvUpdateList.Items.Add(lvItem);
194

            }
195

        }
196


197

        private void UpdateUIInfo(int i, string message)
198

        {
199

            pbUpdate.Value = i + 1;
200

            lblState.Text = message;
201

            lblState.Update();
202

        }
203


204

        private void BroadCastOnUpdateComplete()
205

        {
206

            if (OnUpdateComplete != null)
207

            {
208

                OnUpdateComplete();
209

            }
210

        }
211


212

        private void DownLoadUpdateFiles()
213

        {
214

            if (updateList == null || updateList.Count < 1)
215

            {
216

                BroadCastOnUpdateComplete();
217

                return;
218

            }
219


220

            try
221

            {
222

                UpdateUI dUpdateUI = new UpdateUI(UpdateUIInfo);
223

                AsycDownLoadFile dAsycDownLoadFile = new AsycDownLoadFile(DownLoadFile);
224

                for (int i = 0; i < updateList.Count; i++)
225

                {
226

                    string file = updateList[i];
227

                    string destFile = String.Concat(updateTmpPath, "\\", file);
228

                    string destFileName = destFile.Substring(destFile.LastIndexOf("/") + 1);
229

                    string srcFile = String.Concat(url, file);
230

                    var srcFileName = file.Trim('/');
231

                    destFile = destFile.Replace("/", "\\");
232

                    Directory.CreateDirectory(destFile.Substring(0, destFile.LastIndexOf("\\")));
233

                    string curentFile = String.Concat("正在更新第", i + 1, "/", updateList.Count, "", file);
234

                   
235

                    Invoke(dAsycDownLoadFile, new object[] { srcFileName, srcFileName, i });
236

                    Thread.Sleep(50);
237

                    Invoke(dUpdateUI, new object[] {i, curentFile});
238

                }
239

            }
240

            catch (Exception ex)
241

            {
242

                Debug.WriteLine(ex.Message);
243

            }
244


245

            BroadCastOnUpdateComplete();
246

        }
247


248

        
249


250

        private void CopyUpdateFiles(string srcPath, string destPath)
251

        {
252

            string[] files = Directory.GetFiles(srcPath);
253

            for (int i = 0; i < files.Length; i++)
254

            {
255

                string srcFile = files[i];
256

                string destFile = string.Concat(destPath, "\\", Path.GetFileName(srcFile));
257

                try
258

                {
259

                    File.Copy(srcFile, destFile, true);
260

                }
261

                catch (System.IO.IOException  ex)
262

                {
263

                    
264

                    
265

                }
266

                 
267

            }
268


269

            string[] dirs = Directory.GetDirectories(srcPath);
270

            for (int i = 0; i < dirs.Length; i++)
271

            {
272

                srcPath = dirs[i];
273

                string tmpDestPath = String.Concat(destPath, "\\", Path.GetFileName(srcPath));
274

                Directory.CreateDirectory(tmpDestPath);
275

                CopyUpdateFiles(srcPath, tmpDestPath);
276

            }
277

        }
278


279


280


281

        /// <summary>
282

        /// 更新完成後,要執行的動做(將下載的文件從臨時目錄複製到主目錄,重啓主程序)
283

        /// <remark> 
284

        /// Author:ZhangRongHua 
285

        /// Create DateTime: 2009-6-21 12:25
286

        /// Update History:     
287

        ///  </remark>
288

        /// </summary>
289

        /// <param name="srcPath">The SRC path.</param>
290

        /// <param name="destPath">The dest path.</param>
291

        private void ExecuteUpdate(string srcPath, string destPath)
292

        {
293

            if (errorList != null && errorList.Count < 1)
294

            {
295

                lblInfo.Text = "正在執行更新";
296

                lblInfo.Update();
297

                CopyUpdateFiles(srcPath, destPath);
298

                File.Copy(tmpUpdateFile, locFile, true);
299

            }
300

            Process.Start(Updater.MainProgram);
301


302

            Close();
303

        }
304


305

        private void DownLoadFile(string srcFile, string destFile, ListViewItem lvItem)
306

        {
307

            try
308

            {
309

                DownLoadFile(srcFile, destFile);
310

                lvItem.SubItems.Add("Ok");
311

             }
312

            catch (Exception ex)
313

            {
314

                Debug.WriteLine(ex.Message);
315

                lvItem.SubItems.Add("fail");
316

                ErrorInfo errorInfo = new ErrorInfo();
317
View Code

C#中三層架構的實現介紹web

這篇文章討論如何在C#中實現三層架構,使用MS Access數據庫存儲數據。在此,我在3層架構中實現一個小型的可複用的組件保存客戶數據。並提供添加,更新,查找客戶數據的功能。
背景
首先,我介紹一些3層架構的理論知識。簡單說明:什麼是3層架構?3層架構的優勢是什麼?
什麼是三層架構?
3層架構是一種「客戶端-服務器」架構,在此架構中用戶接口,商業邏輯,數據保存以及數據訪問被設計爲獨立的模塊。主要有3個層面,第一層(表現層,GUI層),第二層(商業對象,商業邏輯層),第三層(數據訪問層)。這些層能夠單獨開發,單獨測試。
爲何要把程序代碼分爲3層。把用戶接口層,商業邏輯層,數據訪問層分離有許多的優勢。
在快速開發中重用商業邏輯組件,咱們已經在系統中實現添加,更新,刪除,查找客戶數據的組件。這個組件已經開發而且測試經過,咱們能夠在其餘要保存客戶數據的項目中使用這個組件。
系統比較容易遷移,商業邏輯層與數據訪問層是分離的,修改數據訪問層不會影響到商業邏輯層。系統若是從用SQL Server存儲數據遷移到用Oracle存儲數據,並不須要修改商業邏輯層組件和GUI組件
系統容易修改,假如在商業層有一個小小的修改,咱們不須要在用戶的機器上重裝整個系統。咱們只須要更新商業邏輯組件就能夠了。
應用程序開發人員能夠並行,獨立的開發單獨的層。
代碼
這個組件有3層,第一個層或者稱爲GUI層用form實現,叫作FrmGUI。第二層或者稱爲商業邏輯層,叫作BOCustomer,是Bussniess Object Customer的縮寫。最後是第三層或者稱爲數據層,叫作DACustomer,是Data Access Customer的縮寫。爲了方便,我把三個層編譯到一個項目中。
用戶接口層
下面是用戶接口成的一段代碼,我只選取了調用商業邏輯層的一部分代碼。
 
//This function get the details from the user via GUI
 
//tier and calls the Add method of business logic layer.
 
private void cmdAdd_Click(object sender, System.EventArgs e)
 
{
 
try
 
{
 
cus = new BOCustomer();
 
cus.cusID=txtID.Text.ToString();
 
cus.LName = txtLName.Text.ToString();
 
cus.FName = txtFName.Text.ToString();
 
cus.Tel= txtTel.Text.ToString();
 
cus.Address = txtAddress.Text.ToString();
 
cus.Add();
 
}
 
catch(Exception err)
 
{
 
MessageBox.Show(err.Message.ToString());
 
}
 
}
 
//This function gets the ID from the user and finds the
 
//customer details and return the details in the form of
 
//a dataset via busniss object layer. Then it loops through
 
//the content of the dataset and fills the controls.
 
private void cmdFind_Click(object sender, System.EventArgs e)
 
{
 
try
 
{
 
String cusID = txtID.Text.ToString();
 
BOCustomer thisCus = new BOCustomer();
 
DataSet ds = thisCus.Find(cusID);
 
DataRow row;
 
row = ds.Tables[0].Rows[0];
 
//via looping
 
foreach(DataRow rows in ds.Tables[0].Rows )
 
{
 
txtFName.Text = rows["CUS_F_NAME"].ToString();
 
txtLName.Text = rows["CUS_L_NAME"].ToString();
 
txtAddress.Text = rows["CUS_ADDRESS"].ToString();
 
txtTel.Text = rows["CUS_TEL"].ToString();
 
}
 
}
 
catch (Exception err)
 
{
 
MessageBox.Show(err.Message.ToString());
 
}
 
}
 
//this function used to update the customer details.
 
private void cmdUpdate_Click(object sender, System.EventArgs e)
 
{
 
try
 
{
 
cus = new BOCustomer();
 
cus.cusID=txtID.Text.ToString();
 
cus.LName = txtLName.Text.ToString();
 
cus.FName = txtFName.Text.ToString();
 
cus.Tel= txtTel.Text.ToString();
 
cus.Address = txtAddress.Text.ToString();
 
cus.Update();
 
}
 
catch(Exception err)
 
{
 
MessageBox.Show(err.Message.ToString());
 
}
 
}
 
商業邏輯層
下面是商業邏輯層的全部代碼,主要包括定義customer對象的屬性。但這僅僅是個虛構的customer對象,若是須要能夠加入其餘的屬性。商業邏輯層還包括添加,更新,查找,等方法。
商業邏輯層是一箇中間層,處於GUI層和數據訪問層中間。他有一個指向數據訪問層的引用cusData = new DACustomer().並且還引用了System.Data名字空間。商業邏輯層使用DataSet返回數據給GUI層。
using System;
using System.Data;
namespace _3tierarchitecture
{
///
/// Summary description for BOCustomer.
///
public class BOCustomer
{
//Customer properties
private String fName;
private String lName;
private String cusId;
private String address;
private String tel;
private DACustomer cusData;
 
public BOCustomer()
{
//An instance of the Data access layer!
cusData = new DACustomer();
}
///
/// Property FirstName (String)
///
public String FName
{
get
{
return this.fName;
}
set
{
try
{
this.fName = value;
if (this.fName == "")
{
throw new Exception(
"Please provide first name ...");
}
}
catch(Exception e)
{
throw new Exception(e.Message.ToString());
}
}
}
///
/// Property LastName (String)
///
public String LName
{
get
{
return this.lName;
}
set
{
//could be more checkings here eg revmove ' chars
//change to proper case
//blah blah
this.lName = value;
if (this.LName == "")
{
throw new Exception("Please provide name ...");
}
}
}
///
/// Property Customer ID (String)
///
public String cusID
{
get
{
return this.cusId;
}
set
{
this.cusId = value;
if (this.cusID == "")
{
throw new Exception("Please provide ID ...");
}
}
}
///
/// Property Address (String)
///
public String Address
{
get
{
return this.address;
}
set
{
this.address = value;

if (this.Address == "")
{
throw new Exception("Please provide address ...");
}
}
}
///
/// Property Telephone (String)
///
public String Tel
{
get
{
return this.tel;
}
set
{
this.tel = value;
if (this.Tel == "")
{
throw new Exception("Please provide Tel ...");
}
}
}
 
///
/// Function Add new customer. Calls
/// the function in Data layer.
///
public void Add()
{
cusData.Add(this);
}
///
/// Function Update customer details.
/// Calls the function in Data layer.
///
public void Update()
{
cusData.Update(this);
}
///
/// Function Find customer. Calls the
/// function in Data layer.
/// It returns the details of the customer using
/// customer ID via a Dataset to GUI tier.
///
public DataSet Find(String str)
{
if (str == "")
throw new Exception("Please provide ID to search");
DataSet data = null;
data = cusData.Find(str);
return data;
}
}
}
 
數據訪問層
數據層包括處理MS Access數據庫的細節。全部這些細節都是透明的,不會影響到商業邏輯層。數據訪問層有個指向商業邏輯層的引用BOCustomer cus。爲了應用方便而且支持其餘數據庫。
 
View Code

Filter與updatebatch混合使用實現批量更新sql

/*******部分代碼*******/
/*******idArr()和codeArr()爲兩個數組,其中,idArr()爲filter數據過濾條件,codeArr()做爲更新數據**********/
.......
 
dim CRs,sql,FStr
sql=""

conn.begintrans
set CRs=server.CreateObject("adodb.recordset")
CRs.ActiveConnection=conn
CRs.CursorType=1
CRs.LockType=3
CRs.Source="select * from MB_DCManage"
CRs.Open
for i=0 to ubound(codeArr)-1
FStr="DCM_ID="&idArr(i) '定義數據過濾
CRs.Filter=FStr 
CRs("DCM_Code")=codeArr(i)
next
CRs.UpdateBatch(3) '批量更新
........
/***********避免重複的進行open操做,可是filter自己也有效率問題;應該結合事務處理;filter可進行多條件選擇;updateBatch各參數-----adAffectCurrent(1):當前位置;
adAffectGroup(2) :符合filter的數據
adAffterAll(3) :當前全部數據***************/
 
View Code

WinForm App自動更新(Live Update)架構數據庫

WinForm App自動更新(Live Update)架構
2010-06-22  來自:博客園  字體大小:【大 中 小】
· 摘要:作了一個小系統,在發佈了第一個可用版本以後,順便實現了自動更新功能。以前沒有這方面的經驗,也沒有翻閱相關資料,本身想了一個簡單的思路,若有笑話之處,懇請批評指正。
· 
一. 基本思路
     一直作Web Form開發,最近開始嘗試了一下Win Form,作了一個小系統,在發佈了第一個可用版本以後,順便實現了自動更新功能。以前沒有這方面的經驗,也沒有翻閱相關資料,本身想了一個簡單的思路,若有笑話之處,懇請批評指正。
    基本上就是這樣的:
    客戶端有兩個子程序,簡單的講就是兩個EXE,一個主的應用程序,一個自動Live Update程序,而在服務端,是一個WCF,提供程序版本更新信息和更新文件。
     每當程序啓動(或手動點「檢測更新」),主程序會調用服務端的WCF檢測更新,若檢測到新版本,則啓動Live Update程序,同時關閉自身。
     Live Update啓動後,調用服務端WCF,獲取文件列表,而後直接下載更新文件並覆蓋本地文件。完畢後啓動主程序,同時關閉自身,這樣,一次自動更新就完了。
二. 系統架構
    


三. 序列圖
    



四. 其它
1. 檢測新版本
     在WCF中會有一個XML配置文件,用於客戶檢測版本和更新文件。
    
2. 下載文件以及覆蓋舊文件
     Live Update下載文件後先保存在臨時文件夾,下載完畢後再從臨時文件夾覆蓋主應用程序的舊文件。防止自動更新中途失敗致使主應用程序不可用。

3. WCF Contract(僅供參考)

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.ServiceModel;



namespace WendyFinance.UpdateCenter.Contract {



     [ServiceContract]

    public interface IAutoUpdate {



         [OperationContract]

        bool CheckUpdate(string clientVersion);



         [OperationContract]

        string GetCurrentVersion();



         [OperationContract]

        string GetUpdateDescription();



         [OperationContract]

         List<string> GetFileList();



         [OperationContract]

        string GetFile(string fileName);

     }

}
 
View Code

版本的自動更新編程

除了在軟件架構設計中須要規劃好各功能項以備分別能夠實現局部升級外,重要的是配置好自動升級組件。然而該自動升級組件並不是直接引用便可,它須要遵照必定的規則部署才能完成自動升級。如下給出它的配置手冊。 必備的文件清單:
 
 
 
文件名 功能描述
AppStart.exe 相似中介代理的程序,由它來啓動真正的應用程序。不直接啓動主應用程序是爲了防止主應用程序升級的過程當中被鎖死而形成升級失敗。
AppStart.config AppStart.exe的配置文件,它指定要啓動的應用程序所在目錄,以及要啓動應用程序的名稱
appupdater.dll 最重要的部件,自動升級的主要組件
system.Resources.dll 資源文件
mscorlib.Resources.dll 核心資源文件
UpdateVersion.xml 服務器端版本升級配置文件
自動升級配置:
 
 
 
注意事項:
 
 
 
1.  由於自動升級組件appupdater代碼裏寫死的緣由,AppStart.config和AppStart.exe是不能更名的!
 
 
 
2.  服務器端最好使用Windows 2000 Server .  使用Windows 2003 Server 會由於網絡安全策略形成訪問不了服務器目錄資源,升級失敗。
 
 
 
3.  服務器端須要把提供升級的該站點配置爲容許目錄瀏覽。
 
 
 
4.  文件的層次結構必須以下配置: 
客戶端執行程序目錄結構以下
 
 
 
 AppStart.exe (不能更名) 
 AppStart.config (不能更名) 
 ClientExe (這個目錄名稱能夠自定,但必須同時修改AppStart.config的AppFolderName項內容) 
  TrySmartClient.exe(這個是自定的主應用程序)
  appupdater.dll (自動升級組件)
其中AppStart.config內容以下:
 
 
 
<Config>
 
 
 
  <AppFolderName>ClientExe</AppFolderName>
 
 
 
  <AppExeName>TrySmartClient.exe</AppExeName> 
 
 
 
</Config> 
AppStart.config解釋:
 
 
 
<AppFolderName>ClientExe</AppFolderName>
 
 
 
告訴AppStart.exe要尋找的主應用程序目錄名稱。 
<AppExeName>TrySmartClient.exe</AppExeName>
 
 
 
告訴AppStart.exe要尋找的主應用程序名。
 
 
 
服務器端目錄結構(該目錄須要設置爲容許目錄瀏覽):
 
 
 
 UpdateVersion.xml (必須,不能更名) 
 Ver (可自定,但必須同時修改UpdateVersion.xml的ApplicationUrl項內容) 
  TrySmartClient.exe (新版本主應用程序)
  mscorlib.Resources.dll (資源文件)
  system.Resources.dll(資源文件)
其中UpdateVersion.xml內容以下:
 
 
 
<VersionConfig>
 
 
 
    <AvailableVersion>6.0.0.0</AvailableVersion>
 
 
 
    <ApplicationUrl>http://YourServerDomainName/SmartServer/Ver/</ApplicationUrl>
 
 
 
</VersionConfig>
 
 
 
UpdateVersion.xml解釋:
 
 
 
<AvailableVersion>6.0.0.0</AvailableVersion>
 
 
 
告訴客戶端目前可用的版本,客戶端appupdater組件會比較本地主應用程序版本號和該項配置的版本號,若是比本地的版本號更高,則進行下載更新。
 
 
 
<ApplicationUrl>http://YourServerDomainName/SmartServer/Ver/</ApplicationUrl>
 
 
 
告訴客戶端到哪一個網址進行下載更新
 
 
 
按上述目錄結構和配置文件內容,appupdater組件的關鍵屬性配置應該以下:
 
 
 
AutoFileLoad :True
ChangeDetectionMode ServerManifestCheck
UpdateUrl http://YourServerDomainName/SmartServer/UpdateVersion.xml
appupdater組件關鍵屬性配置解釋:
 
 
 
AutoFileLoad = true  //容許自動文件裝載
 
 
 
ChangeDetectionMode :ServerManifestCheck  //檢測模式:根據配置文件進行檢測,也就是UpdateUrl屬性指定的文件。
 
 
 
UpdateUrl :指定自動升級組件檢測服務器端升級配置文件統一資源定位位置和文件名。(也就是網址)
 
 
 
上述配置在.Net Framework 1.1 和Windows2000下測試經過. appupdater自動升級組件下載地址:http://c2c.6688.com/updateDown/appupdater.rar
 
 
 
如今咱們來將它應用在實例中。
 
 
 
第一步:創建應用程序來進行更新
 
 
 
在這一步咱們將創建應用程序來演示如何實現自動更新。
 
 
 
1.        使用VS.NET生成一個新的Windows應用項目,命名爲「SampleApp」。
 
 
 
2.        給窗體一個你選擇的有趣的背景色。咱們將使用背景色來與後面更新的版本區別。
 
 
 
3.        如今讓咱們給這個應用程序增長一個細微的功能,首先給你的窗體增長一個按鈕。壓縮文件中包含一個擁有簡單Windows窗體的程序集。給壓縮文件中Samples\SampleApp\SimpleForm程序集增長一個引用。而後在你的按鈕事件句柄中添加兩行代碼:
 
 
 
    SimpleForm.Form1 F = new SimpleForm.Form1();
 
 
 
    F.Show();
 
 
 
4.        將你的build標誌從debug轉換爲RELEASE。這將容許咱們避免稍後當咱們生成一個應用程序的新版本而同時原始拷貝正在運行產生的pdb文件鎖定問題。
 
 
 
生成並測試你的應用程序。
 
 
 
第二步:添加.NET應用程序更新組件
 
 
 
在這一步咱們將給SampleApp添加.NET應用程序更新組件。
 
 
 
1.        在VS.NET工具欄的組件標籤上,右擊選擇「自定義工具欄」。選擇‘.NET框架組件’標籤。點「瀏覽」並選擇位於壓縮文件中AppUpdater項目下的AppUpdater.dll,單擊OK。
 
 
 
2.        一個AppUpdater圖標如今應該出如今工具欄的組件列表的底部。將AppUpdater組件拖放到SampleApp窗體上。一個名爲appUpdater1的.NET應用程序更新組件的實例會出如今窗體的底部。
 
 
 
第三步:設置.NET應用程序更新組件  
 
 
 
在這一步咱們將設置.NET應用程序更新組件。注意這個示例你只需改變最開始的四個屬性,其它的,默認值就夠了。
 
 
 
AppUpdater  屬性 ――這是.NET Application應用程序更新的核心,對於本程序須要作如下設置:
 
屬性名稱 描述
AutoFileLoad 這個控制後面要描述的命令下載特徵,如今將它設置爲true。
ChangeDetectionMode 該枚舉決定如何爲更新進行檢查。在該例中,咱們將使用一個服務器顯式檢查,所以將這個值設置爲「ServerManifestCheck」。
ShowDefaultUI .NET應用程序更新組件具備一系列用戶界面來通知用戶一些事件,對於該例咱們將使用默認的用戶界面,所以將這個值設置爲true。
UpdateUrl UpdateUrl是決定更新程序到何處去尋找更新的。在該例中設置爲服務器顯式文件的URL:   http://yourWebserver/SampleApp_ServerSetup/UpdateVersion.xml.    用你的Web服務器名稱來代替」yourWebserver」
 
 
 
Downloader 屬性――AppUpdater組件有兩個子組件。第一個稱之爲Downloader,它控制組件的下載和安裝。下面是該屬性的描述,對於個人示例來講默認的屬性值就能工做的很好。
 
 
 
屬性名稱 描述
DownloadRetryAttempts 在下載期間若是有錯誤發生(好比Web服務器宕機)downloader會稍後重試。這個屬性控制downloader認爲是完全的應用程序更新錯誤以前重試網絡請求的次數。
SecondsBeteweenDownloadRety 重試網絡請求以前等待的秒數。
UpdateRetryAttempts 這個屬性控制試圖更新的次數。
ValidateAssemblies 這個屬性控制下載程序集有效完成的級別。更多信息參見這篇文章的安全一節。
Poller 屬性――AppUpdater的第二個子組件是Poller。Poller控制更新檢查。下面是該屬性的描述,對於咱們的示例而言,全部的默認屬性值就工做的很好。
 
 
 
屬性名稱 描述
AutoStart 布爾值,在應用程序啓動時控制Poller是否應當開始輪詢或它是否應當等待直到有計劃的顯式開始。
DownloadOnDetection 布爾值,控制Poller在一個新的更新發現時是否當即開始下載更新,或者是否經過調用DownloadUdpate()方法必須開始顯式下載。
InitialPollInterval 應用程序啓動後在第一次執行更新檢查前等待的秒數。
PollInterval 第一次更新檢查以後,PollInterval控制後續每次更新檢查之間間隔的秒數,注意:默認爲每30秒進行一次檢查。
全部這一切完成以後,你的屬性表格看起來應當是下面這個樣子:Samples\SampleApp\SampleApp_Complete目錄包含應用程序正確安裝的一個版本。
 
 
 
第四步:生成並在客戶端部署應用程序V1版本。
 
 
 
在這一步咱們將生成應用程序V1版本並將它部署在客戶端。
 
 
 
在SampleApp項目中,打開AssemblyInfo.cs文件。將AssemblyVersion的值從「1.0」修改成「1.0.0.0」.這會引發在生成程序集時得到值爲「1.0.0.0」的標記,該標記代替VS.NET一般指定爲遞增的值。
 
 
 
1.        生成應用程序。
 
 
 
2.        從壓縮文件中將Samples\SampleApp\SampleApp_ClientSetup目錄拷貝到你的本地機器上。要注意SampleApp_ClientSetup目錄已經包含了AppStart.exe。AppStart.config已經設置爲指向1.0.0.0目錄而且啓動SampleApp.exe。
 
 
 
從SampleApp的release生成目錄下拷貝SampleApp(Appupdater.dll,SimpleForm.dll和SampleApp.exe)到你客戶端的SampleApp_ClientSetup\1.0.0.0目錄下。
 
 
 
在這個時候,一個功能完整的應用程序版本應當被「安裝」到了客戶端,能夠經過運行AppStart.exe來執行。
 
 
 
第五步:安裝Web服務器
 
 
 
在這一步咱們將安裝Web服務器以在輪詢應用程序更新時使用。.NET應用程序更新組件使用HTTP-DAV來下載應用程序更新所以須要一個支持HTTP-DAV的Web服務器。Windows 2000上的IIS5.0和更新的操做系統都支持HTTP-DAV。
 
 
 
1.        從壓縮文件中將Samples/SampleApp_ServerSetup目錄拷貝到你的Web服務器上的wwwroot目錄下。
 
 
 
2.        爲了完整,將SampleApp的V1版本拷貝到Web服務器的1.0.0.0文件夾。
 
 
 
3.        在你的Web服務器上爲SampleApp_ServerSetup目錄啓用IIS的「目錄瀏覽」。
 
 
 
第六步:自動更新應用程序
 
 
 
OK,如今是時間來經過自動安裝一個新版原本看看以上這些艱苦工做的結果了。
 
 
 
1.        若是你部署在客戶端的SampleApp版本沒有運行,加載它讓它運行。記得使用AppStart.exe。
 
 
 
2.        回到VS.NET並在SampleApp窗體中作一些能夠被注意到的修改(好比修改背景色)。
 
 
 
3.        將AssemblyInfo.cs的版本信息修改成2.0.0.04.        從新生成。
 
 
 
5.        回到Web服務器並生成一個和1.0.0.0目錄同等的目錄2.0.0.0。從release生成目錄下將新版本應用程序拷貝到Web服務器上新建的2.0.0.0目錄下。
 
 
 
6.        打開UpdateVersion.xml並修改AvailableVersion爲2.0.0.0。修改ApplicationURL爲指向新的2.0.0.0路徑。
 
 
 
7.        保存對UpdateVersion.xml所作的修改。
 
 
 
一旦你保存了新的UpdateVersion.xml,在30秒以內,運行中的SampleApp拷貝將會探測到新的可用的版本。SampleApp將下載新版本,實現更新,並彈出默認的用戶界面詢問用戶是否但願重啓並當即開始使用新版本。單擊「Yes」迴應該對話框。SampleApp將會重啓並運行新版本。若是你查看客戶端SampleApp的部署,你會注意到如今在原始的1.0.0.0的目錄後有一個2.0.0.0的目錄。1.0.0.0目錄將會在下一次更新發生時被清空。
 
 
 
 
 
 
若是因爲某種緣由,你沒法使得.NET應用程序更新器工做。在你深刻調試以前肯定如下幾點,你遇到的問題極可能就是以下之一:
 
 
 
• 你是否將IIS目錄瀏覽給打開了?若是沒有,更新器將不會下載安裝任何文件。
 
 
 
• 你是否正確的部署了一切並正確設置了URL?
 
 
 
• 若是你的應用程序安裝在program files目錄下,肯定你是該機的超級管理員或超級用戶嗎?若是不是,你將不會有寫權限來更新應用程序。
 
 
 
• 你是在應用程序的主用戶界面線程中生成AppUpdater對象的嗎?若是不是,更新器將不能顯示用戶界面而且在激發事件回到用戶界面時失敗。
 
 
 
• 是否更新成功,但應用程序使用新的更新自動重啓時失敗?.NET應用程序更新組件試圖經過調用Application.Exit方法來重啓應用程序。然而,該方法並不能保證關閉一個應用程序。若是你生成並遺留了單獨的線程在運行,該方法就沒法關閉進程。保證全部線程終止的解決的方案是經過調用Application.OnExit事件,或者掛鉤.NET應用程序更新器的OnUpdateComplete事件並本身處理關閉。
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
View Code

編寫組件,使用JavaScript更新UpdatePanelwindows

衆所周知,UpdatePanel是經過Trigger來更新的。被設定爲Trigger的控件在PostBack以後會被客戶端所截獲,而且使用 XMLHttpRequest對象發送內容,而後服務器端由ScriptManager配合,改變Page對象的輸出,最後獲得部分刷新的效果。可是有時 候咱們可能須要使用JavaScript來刷新UpdatePanel,這時候就不太方便了。
  固然,咱們又一個屬於 Workaround的方法,那就是使用JavaScript來模擬按鈕的點擊。咱們每每會將一個按鈕設爲某個UpdatePanel的Trigger, 而後在客戶端模擬它的點擊(我後面會提到,其實這是一個比較糟糕的作法,沒有必要),使UpdatePanel進行更新。可是這樣的作法實在太麻煩了些, 也至關的不優雅。
  如今咱們就來編寫一個組件解決這個問題。這個組件的名字叫作JavaScriptUpdater,彷佛取得不怎麼樣——我一直不擅長取名。
 
首先來定一個需求吧
  咱們的目的,其實就是爲了在客戶端生成一個 JavaScript代理,提供一個方法,調用它以後可以刷新頁面。若是一個UpdatePanel的UpdateMode爲Always,那麼它必定會 更新。若是須要更新UpdateMode爲Conditional的UpdatePanel,就須要經過在頁面中編寫tag來設定哪些 UpdatePanel也會被更新。咱們須要儘量的把編程工做變得最小。
  不如咱們先考慮使用方式,咱們編寫的這個JavaScriptUpdater在頁面中能夠這樣使用:
JavaScriptUpdater使用方式
<helper:JavaScriptUpdater runat="server" ID="Updater" MethodName="Refresh"
ResolveUpdatePanel="OnResolveUpdatePanel" Enabled="True">
<UpdatePanels>
<helper:UpdatePanel UpdatePanelID="UpdatePanel1" />
...
</UpdatePanels>
</helper:JavaScriptUpdater>
 
  JavaScriptUpdater有一個 簡單屬性MethodName,代表了在客戶端生成代理方法的名字。再上例中該屬性爲Refresh,代表咱們會調用 UpdatePanels.Refresh()方法進行UpdatePanel更新。UpdatePanels是一個集合屬性,能夠指定哪些 UpdateMode爲Conditional的UpdatePanel一同進行更新。若是某個UpdatePanelID沒有找到的話,就會調用 ResolveUpdatePanel事件,讓用戶來指定一個UpdatePanel。還有一個Enabled屬性,用於控制該 JavaScriptUpdater是否生效。
  一個頁面裏可以放置多個JavaScriptUpdater,這樣能夠生成多個JavaScript代理方法。這樣的設定,應該已經足夠用了。
 
實現JavaScriptUpdater
  天然,咱們先定義最簡單的兩個類,UpdatePanelHelper.UpdatePanel類,和ResolveUpdatePanelEventArgs類。因爲實在簡單,就直接貼一下代碼了:
UpdatePanel類
namespace UpdatePanelHelper
{
public class UpdatePanel
{
private string _UpdatePanelID;
public string UpdatePanelID
{
get { return _UpdatePanelID; }
set { _UpdatePanelID = value; }
}
}
}
ResolveUpdatePanelEventArgs類
namespace UpdatePanelHelper
{
public class ResolveUpdatePanelEventArgs : EventArgs
{
private string _ID = null;
public string ID
{
get { return _ID; }
}
private System.Web.UI.UpdatePanel _UpdatePanel = null;
public System.Web.UI.UpdatePanel UpdatePanel
{
get { return _UpdatePanel; }
set { _UpdatePanel = value; }
}
public ResolveUpdatePanelEventArgs(string id)
{
this._ID = id;
}
}
}
 
  而後開始考慮編寫最關鍵的JavaScriptUpdater類。首先定義它的簡單框架,以下:
JavaScriptUpdater控件的整體框架與屬性定義
namespace UpdatePanelHelper
{
[PersistChildren(false)]
[ParseChildren(true)]
[NonVisualControl]
public class JavaScriptUpdater : Control
{
private bool initialized = false;
private bool _Enabled = true;
public bool Enabled
{
get
{
return this._Enabled;
}
set
{
if (this.initialized)
{
throw new InvalidOperationException(
                        "Cannot set the property after initialized.");
}
this._Enabled = value;
}
}
private string _MethodName;
public string MethodName
{
get
{
return this._MethodName;
}
set
{
if (this.initialized)
{
throw new InvalidOperationException(
                        "Cannot set the property after initialized.");
}
this._MethodName = value;
}
}
public event EventHandler<ResolveUpdatePanelEventArgs> ResolveUpdatePanel;
private List<UpdatePanel> _UpdatePanels = new List<UpdatePanel>();
[PersistenceMode(PersistenceMode.InnerProperty)]
public List<UpdatePanel> UpdatePanels
{
get
{
return _UpdatePanels;
}
}
...
}
}
 
  咱們使用一個initialized變量來 確保Enabled或MethodName屬性只能在頁面Init時進行修改。因爲控件會在多個生命週期中進行操做,若是不作這樣的限制,會讓控制變得繁 瑣,容易出錯。從下面的代碼中會發現,咱們會在響應頁面的InitComplete事件時將initialized變量設爲true。
  咱們在這裏實現JavaScript更新UpdatePanel的作法,和傳統的方法殊途同歸,只是咱們這裏將動態添加按鈕,而且在這裏咱們使用LinkButton。咱們將響應Page對象的Load事件,添加那個做爲Trigger的LinkButton。以下:
動態添加LinkButton
private string clientButtonId = null;
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
this.Page.InitComplete += new EventHandler(Page_InitComplete);
}
private void Page_InitComplete(object sender, EventArgs e)
{
    this.initialized = true;

if (this.Enabled)
{
this.Page.Load += new EventHandler(Page_Load);
this.Page.PreRenderComplete += new EventHandler(Page_PreRenderComplete);
}
}
private void Page_Load(object sender, EventArgs e)
{
LinkButton button = new LinkButton();
button.Text = "Update";
button.ID = this.ID + "Button";
button.Style[HtmlTextWriterStyle.Display] = "none";
button.Click += new EventHandler(OnTrigger);
this.Page.Form.Controls.Add(button);
this.clientButtonId = button.ClientID;
ScriptManager.GetCurrent(this.Page).RegisterAsyncPostBackControl(button);
}
 
  咱們在頁面的 Page_InitComplete事件中判斷Enabled屬性是否爲true(這時Enabled屬性已經不能修改了),若是Enabled爲 ture,則響應頁面的Load事件,用於動態添加一個LinkButton。請注意,咱們並不會將它的Visible屬性設爲False,不然它的 HTML將不會出如今頁面上。咱們應該將它Style的display設爲none,這樣它既能在頁面結構中出現,也不會顯示出來。在添加了這個 LinkButton以後,將會保留它的ClientID,而且找出當前頁面的ScriptManager,調用 RegisterAsyncPostBackControl方法,將這個LinkButton註冊爲異步刷新頁面的控件。
  之前,我寫給別人範例都是使用了一個 Button做爲Trigger,而後在客戶端使用JavaScript對它進行點擊。這其實不是很合理,比較好的作法其實使用LinkButton。要 說明這個問題的緣由,咱們須要看一下LinkButton在頁面中生成的HTML元素。很顯然,這是個<a />,以下:
LinkButton生成的HTML
<a id="UpdaterButton" href="javascript:__doPostBack('UpdaterButton','')">Update</a>
 
  請注意它的href,它代表了點擊該元素會 執行這個JavaScript代碼。發現了不?咱們何須模擬元素的點擊,咱們直接調用__doPostBack函數不就好了?Cool!因而咱們如今也可 以輕易得出,在響應頁面的PreRenderComplete事件時須要註冊的Script腳本了。以下:
在PreRenderComplete事件中註冊腳本
private const string BasicScripts =
@"if (!window.UpdatePanels) window.UpdatePanels = {};
UpdatePanels._createUpdateMethod = function(btnId)
{
return function()
{
__doPostBack(btnId, '');
}
}";
private const string RegisterMethodTemplate =
"\nUpdatePanels['{0}'] = UpdatePanels._createUpdateMethod('{1}');";
private void Page_PreRenderComplete(object sender, EventArgs e)
{
this.Page.ClientScript.RegisterClientScriptBlock(
this.GetType(),
"BasicScripts",
JavaScriptUpdater.BasicScripts,
true);
this.Page.ClientScript.RegisterClientScriptBlock(
this.GetType(),
this.clientButtonId,
String.Format(JavaScriptUpdater.RegisterMethodTemplate,
            this.MethodName, this.clientButtonId),
true);
}
 
  首先會註冊一些基礎腳本,咱們會使用相同的 Type和Key參數,這樣保證了這段代碼只會被註冊一次。在註冊每一個代理方法的腳本時,就會使用該腳本的clientButtonId做爲key,保證 了每段腳本都會被註冊成功。順便一提,咱們在這裏直接使用了Page的ClientScriptManager來註冊腳本,保證了在異步更新 UpdatePanel時,不會將腳本發送到客戶端去。
  可能有朋友會出現疑惑,爲何咱們須要在頁 面的PreRenderComplete事件中註冊腳本呢?在頁面的Load事件中一併註冊了不能夠嗎?答案是,由於ScriptManager也是在這 時候註冊ASP.NET AJAX的基礎腳本,咱們如今這麼作是爲了保證了咱們註冊的腳本出如今ASP.NET AJAX的腳本以後。
  哦,原來如此……等一下,是否發覺咱們如今 的腳本與ASP.NET AJAX的基礎腳本無關?沒錯,事實上咱們這裏的確能夠方法頁面的Load事件中註冊,我如今這麼作彷佛只是一個習慣——或者說是爲ASP.NET AJAX編寫組件的一個模式——響應頁面的PreRenderComplete事件,用於註冊所需的腳本。
  大部分的工做已經完成了,咱們只須要再響應那個LinkButton的Click事件便可。咱們須要強制更新全部指定的UpdatePanel。代碼以下,很是簡單,就很少做解釋了:
觸發更新
private void OnTrigger(object sender, EventArgs e)
{
if (this.Enabled)
{
foreach (UpdatePanel panel in this.UpdatePanels)
{
System.Web.UI.UpdatePanel updatePanel =
this.FindUpdatePanel(panel.UpdatePanelID);
if (updatePanel != null)
{
updatePanel.Update();
}
}
}
}
private System.Web.UI.UpdatePanel FindUpdatePanel(string id)
{
System.Web.UI.UpdatePanel result = null;
if (id != null)
{
result = this.NamingContainer.FindControl(id)
as System.Web.UI.UpdatePanel;
}
if (result == null)
{
ResolveUpdatePanelEventArgs e = new ResolveUpdatePanelEventArgs(id);
this.OnResolveUpdatePanel(e);
result = e.UpdatePanel;
}
return result;
}
private void OnResolveUpdatePanel(ResolveUpdatePanelEventArgs e)
{
if (this.ResolveUpdatePanel != null)
{
this.ResolveUpdatePanel(this, e);
}
}
 
使用JavaScriptUpdater
  JavaScriptUpdater很是簡單,只需一個最簡單的例子,你們就能夠明白它的使用方式:
JavaScriptUpdater使用示例
<%@ Register Assembly="UpdatePanelHelper" Namespace="UpdatePanelHelper"
 TagPrefix="helper" %>
<asp:UpdatePanel ID="UpdatePanel1" runat="server" UpdateMode="Conditional">
<ContentTemplate>
<%= DateTime.Now.ToString() %>
</ContentTemplate>
</asp:UpdatePanel>
<helper:JavaScriptUpdater runat="server" ID="Updater" MethodName="Refresh">
<UpdatePanels>
<helper:UpdatePanel UpdatePanelID="UpdatePanel1" />
</UpdatePanels>
</helper:JavaScriptUpdater>
<input type="button" onclick="UpdatePanels.Refresh()" value="Refresh" />
 
  點擊最下方定義的按鈕時,會調用 UpdatePanels.Refresh()方法,因而則會更新UpdatePanel1。請注意,UpdatePanel1的UpdateMode爲 Conditional,咱們是經過在JavaScriptUpdater中指定它,用於強制對它進行更新。咱們再看一下它生成的JavaScript代 碼和HTML就會更加清楚它的實現方式了。以下:
在客戶端生成的內容
<script type="text/javascript">
if (!window.UpdatePanels) window.UpdatePanels = {};
UpdatePanels._createUpdateMethod = function(btnId)
{
return function()
{
__doPostBack(btnId, '');
}
}
UpdatePanels['Refresh'] = UpdatePanels._createUpdateMethod('UpdaterButton');
</script>
...
<a id="UpdaterButton"
href="javascript:__doPostBack('UpdaterButton','')"
style="display:none;">Update</a>
 
點擊這裏下載源文件。
 
View Code

利用XMLHTTP實時更新數據數組

傳統上,咱們瀏覽網頁,若是加入最新的數據.只能是等咱們從新向服務器端請求時才能顯示出來.可是,對於一些時效性很強的網站.傳統的這種作法是不能知足的. 咱們可讓程序自動刷新.定時向服務器請求數據.5秒取一次數據,10秒取一次數據.利用XMLHTTP發出請求並取得數據.傳到客戶端,客戶端從新組織並顯示數據.
demo.htm 前臺顯示.
如下是代碼片斷:
<script language="javascript">
function GetResult()
{
/*
*--------------- GetResult() -----------------
* GetResult()
* 功能:經過XMLHTTP發送請求,返回結果.
* 參數:str,字符串,發送條件.
* 實例:GetResult();
*--------------- GetResult() -----------------
*/
var oBao = new ActiveXObject("Microsoft.XMLHTTP");
//特殊字符:+,%,&,=,?等的傳輸解決辦法.字符串先用escape編碼的.
//Update:2004-6-1 12:22
oBao.open("POST","Server.asp",false);
oBao.send();
//服務器端處理返回的是通過escape編碼的字符串.
var strResult = unescape(oBao.responseText);
//將字符串分開.
var arrResult = strResult.split("###");
RemoveRow(); //刪除之前的數據.
//將取得的字符串分開,並寫入表格中.
for(var i=0;i<arrResult.length;i++)
{
arrTmp = arrResult[i].split("@@@");
num1 = arrTmp[0]; //字段num1的值
num2 = arrTmp[1]; //字段num2的值
row1 = tb.insertRow();
cell1 = row1.insertCell();
cell1.innerText = num1;
cell2 = row1.insertCell();
cell2.innerText = num2;
}
}
function RemoveRow()
{
//保留第一行表頭,其他數據均刪除.
var iRows = tb.rows.length;
for(var i=0;i<iRows-1;i++)
{
tb.deleteRow(1);
}
}
function MyShow()
{
//2秒自動刷新一次,2秒取得一次數據.
timer = window.setInterval("GetResult()",2000);
}
</script>
<body onload="MyShow()">
<p>
</p>
<table width="47%" height="23"border="0" cellpadding="1" cellspacing="0" id="tb">
<tr>
<td>num1</td>
<td>num2</td>
</tr>
</table>
Server.asp 後臺讀取數據
如下是代碼片斷:
<% @Language="javascript" %>
<%
function OpenDB(sdbname)
{
/*
*--------------- OpenDB(sdbname) -----------------
* OpenDB(sdbname)
* 功能:打開數據庫sdbname,返回conn對象.
* 參數:sdbname,字符串,數據庫名稱.
* 實例:var conn = OpenDB("database.mdb");
*--------------- OpenDB(sdbname) -----------------
*/
var connstr = "Provider=Microsoft.Jet.OLEDB.4.0; Data Source="+Server.MapPath(sdbname);
var conn = Server.CreateObject("ADODB.Connection");
conn.Open(connstr);
return conn;
}
var sResult = new Array();
var oConn = OpenDB("data.mdb");
//特殊字符:+,%,&,=,?等的傳輸解決辦法.客戶端字符是通過escape編碼的
//因此服務器端先要通過unescape解碼.
//Update:2004-6-1 12:22
var sql = "select num1,num2 from nums order by id";
var rs = oConn.Execute(sql);
while(!rs.EOF)
{
//一條記錄用"###"隔開.每列數據用"@@@"隔開. 這是以只有兩個列數據的狀況.
sResult[sResult.length] = rs("num1").Value + "@@@" + rs("num2").Value
rs.MoveNext();
}
//escape解決了XMLHTTP。中文處理的問題.
Response.Write(escape(sResult.join("###")));
%>
數據庫data.mdb
表 nums
id,自動編號
num1,文本
num2,文本
測試數據
id num1 num2
1 20.70 20.810
2 10.5 20.5
3 12.3 300
4 132 323
5 563 56
6 20 10
 
View Code

利用反射檢查程序集實現自動更新

  在.Net下要讓程序實現自動維護程序集的版本而且實現自動更新到最新版本的功能,可使用反射機制。它提供了檢查程序集的方法,經過 System.Reflection 中的 Assembly 類咱們能夠加載程序集,而後檢查它的版本號,以此判斷是否須要下載或更新。這裏我寫了一個示例來實現這個功能。但最後發現一旦加載了程序集就佔用了須要更新的程序集文件,致使文件替換失敗。爲了解決這個問題,我參考了Flier's Sky的Assembly.Unload和Wayfarer's Prattle的經過應用程序域AppDomain加載和卸載程序集。下面就是個人代碼,因爲時間倉促,估計有些異常尚未處理到。請你們指教。

using System;
using System.IO;
using System.Reflection;
using System.Collections.Generic;
using System.Text;
 
namespace Update
{
    // 序列化這個用來傳遞參數的類
    public class AssembliyInf : MarshalByRefObject
    {
        public string AssemblyName = "";
        public string AssemblyFileFullPath = "";
        public string Version = "";
        public string Revision = "";
        public string Major = "";
        public string Minor = "";
    }
 
    // 因爲是遠程調用的方式,因此這個類也須要序列化
    public class AssemblyLoader : MarshalByRefObject, IDisposable
    {
        public AssembliyInf GetAssemblyInf(string fileFullName)
        {
            AssembliyInf assemblyInf = new AssembliyInf();
 
            try
            {
                Assembly assembly = Assembly.ReflectionOnlyLoadFrom(fileFullName);
 
                assemblyInf.AssemblyName = ((AssemblyName)assembly.GetName()).Name;
                assemblyInf.AssemblyFileFullPath = assembly.Location;
                assemblyInf.Version = ((AssemblyName)assembly.GetName()).Version.ToString();
                assemblyInf.Revision = ((AssemblyName)assembly.GetName()).Version.Revision.ToString();
                assemblyInf.Major = ((AssemblyName)assembly.GetName()).Version.Major.ToString();
                assemblyInf.Minor = ((AssemblyName)assembly.GetName()).Version.Minor.ToString();
 
                assembly = null;     // 釋放引用
 
                // 手工調用框架的垃圾收集器
                System.GC.Collect();
                System.GC.WaitForPendingFinalizers();
                System.GC.Collect(0);
            }
            catch (Exception)
            {
            }
 
            return assemblyInf;
        }
 
        public void Dispose()
        {
 
        }
    }
 
 
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine();
 
            string sourceFile, distinationFile;
            sourceFile = @"D:\MyApp\Update\myApp.exe";          // 假定準備更新的程序集已經下載到本地
            distinationFile = @"D:\MyApp\myApp.exe";            // 這是要維護的目標程序集,發現新版本後就須要替換
 
            // 顯示準備更新的程序集信息
            AssembliyInf assemblyNew = GetAssemblyInf(sourceFile);
            ShowAssembly(assemblyNew);
 
            // 顯示當前使用的程序集信息
            AssembliyInf assemblyCurrent = GetAssemblyInf(distinationFile);
            ShowAssembly(assemblyCurrent);
 
            // 比較兩個程序集
            if (Compare(assemblyNew, assemblyCurrent))
            {
                Console.WriteLine("須要更新當前程序集!");
                // 開始更新
                Update(assemblyNew, assemblyCurrent);
            }
            else
                Console.WriteLine("不須要更新當前程序集!");
 
            Console.ReadKey();
        }
 
        // 用新的程序集替換現有的
        static void Update(AssembliyInf assemblyNew, AssembliyInf assemblyCurrent)
        {
            string sourceFile, distinationFile;
 
            sourceFile = assemblyNew.AssemblyFileFullPath;
            distinationFile = assemblyCurrent.AssemblyFileFullPath;
 
            // 替換文件
            File.Copy(sourceFile, distinationFile, true);
        }
 
        // 顯示程序集相關信息
        static void ShowAssembly(AssembliyInf assembly)
        {
            Console.WriteLine("Assembly Name:             " + assembly.AssemblyName );
            Console.WriteLine("Assembly Version.Current:  " + assembly.Version);
            Console.WriteLine("Assembly Version.Revision: " + assembly.Revision);
            Console.WriteLine("Assembly Version.Major:    " + assembly.Major);
            Console.WriteLine("Assembly Version.Minor:    " + assembly.Minor);
            Console.WriteLine("Assembly FullName:         " + assembly.AssemblyFileFullPath);
            Console.WriteLine();
        }
 
        // 比較兩個程序集判斷是否須要更新
        static bool Compare(AssembliyInf assemblyNew, AssembliyInf assemblyCurrent)
        {
            if ((assemblyNew.AssemblyName == assemblyCurrent.AssemblyName)
                && (int.Parse(assemblyNew.Revision) > int.Parse(assemblyCurrent.Revision)))
                return true;
            else
                return false;
        }
 
        // 獲取程序集的信息
        static AssembliyInf GetAssemblyInf(string fileFullName)
        {
            AssembliyInf assemblyInf = new AssembliyInf();
 
            string dllName = typeof(Program).Assembly.Location;
            AppDomain domain = null;
            AppDomainSetup setup = new AppDomainSetup();
            setup.ShadowCopyFiles = "true";
 
            domain = AppDomain.CreateDomain(dllName, null, setup);
 
            AssemblyLoader al = (AssemblyLoader)domain.CreateInstanceFromAndUnwrap(dllName, "Update.AssemblyLoader");
            AssembliyInf tmpAssemblyInf = al.GetAssemblyInf(fileFullName);
 
            // 因爲使用了序列化致使傳回的對象不能傳出這個方法,因此要轉換一下
            assemblyInf.AssemblyName = tmpAssemblyInf.AssemblyName;
            // 又由於是使用了子程序域的方法,實際執行加載的子程序域是一個臨時文件。返回值是一個臨時文件。
            //assemblyInf.AssemblyFileFullPath = tmpAssemblyInf.AssemblyFileFullPath;
            assemblyInf.AssemblyFileFullPath = fileFullName;
            assemblyInf.Version = tmpAssemblyInf.Version;
            assemblyInf.Major = tmpAssemblyInf.Major;
            assemblyInf.Minor = tmpAssemblyInf.Minor;
            assemblyInf.Revision = tmpAssemblyInf.Revision;
 
            AppDomain.Unload(domain);
 
            return assemblyInf;
        }
    }
 
}
 
View Code

軟件更新程序(使用WinRar壓縮包)

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Net;
using System.Diagnostics;

namespace UpDate
{
public partial class Form1 : Form
{
private WebClient update = new WebClient();

public Form1()
{
InitializeComponent();
}

private void Form1_Load(object sender, EventArgs e)
{
string URL = @"http://files.cnblogs.com/mossan/Zhongwen.rar";
int n = URL.LastIndexOf('/');
string fileName = URL.Substring(n + 1, URL.Length - n - 1);

if (!(Directory.Exists(Application.StartupPath + "\\update")))
{
Directory.CreateDirectory(Application.StartupPath + "\\update");
}

try { update.DownloadFile(URL, Application.StartupPath + "\\update\\" + fileName); }
catch (WebException ex) { MessageBox.Show(ex.Message, "Error"); }

try 
{
Process UnWinrar = new Process();
UnWinrar.StartInfo.FileName = "WinRAR.exe";
UnWinrar.StartInfo.Arguments = "e -o+ \"" + Application.StartupPath + "\\update\\" + fileName + "\"" + " \"" + Application.StartupPath + "\\update" + "\"";
UnWinrar.Start();
MessageBox.Show("解壓縮完成!");
File.Copy(Application.StartupPath + "\\update\\" + "Zhongwen.exe", Application.StartupPath + "\\Zhongwen.exe", true);

Process ProZhongwen = new Process();
ProZhongwen.StartInfo.FileName = Application.StartupPath + "\\Zhongwen.exe";
ProZhongwen.Start();
}
catch (Exception ex) { MessageBox.Show(ex.Message); }
this.Close();
}
}
}
View Code

網站文件更新

在進行網站更新時,每每更新的文件不太多,但文件處於不一樣的目錄中。這樣更新時,既要備份原始文件,又要進行更新,非常麻煩。若是是7個前端機,真是煩不勝煩。因此便有了此工具。
    其實,Xcopy命令已經實現了,咱們只要好好的利用它就能夠。即:先把要更新的複製到備份目錄,而後從目的目錄中把備份目錄中存在的文件複製過來。再把新文件複製過去就能夠了。


@echo off
echo ****************************************************   
echo *** 版本:V1.1                                   ***   
echo *** 功能:把指定目錄中的文件,所有複製到指定目錄 ***   
echo ***       並備份原來已經存在的文件到備份目錄     ***   
echo *** 編寫:河北全通軟件中心 牛昆亮 2009-2.19      ***   
echo ****************************************************   
if "%1"=="" goto input 
if "%2"=="" goto input 
set src=%1
set des=%2
:begin
if "%src%"=="" goto usage 
if "%des%"=="" goto usage 
echo ===============================================
echo             將要執行升級
echo            新文件路徑名  :%src%
echo            原始文件路徑名:%des%
set /p gotoEnd="            按Y繼續,其它退出:"
if not "%gotoEnd%" == "y" goto end
set bakpath=bak_%date:~0,10%%time:~0,2%%time:~3,2%%time:~6,2%
xcopy "%src%\*.*" %bakpath%\ /S 
xcopy "%des%\*.*" %bakpath%\ /S /U /R /Y 
xcopy "%src%\*.*" "%des%\" /S /R

goto end

:input
set /P src=輸入新文件路徑名(如:SrcPath):
set /p des=輸入原始文件路徑名(如:DesPath):
goto begin
:usage
echo usage:update srcpath despath
:end
echo press any key to exit
pause
 
  update-tool.rar
技術交流,歡迎轉載。轉載請註明出處 http://evlon.cnblogs.com QQ:evlion@qq.com
 
View Code

一段簡單軟件更新程序代碼(WinRar壓縮包)

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Net;
using System.Diagnostics;

namespace UpDate
{
public partial class Form1 : Form
{
private WebClient update = new WebClient();

public Form1()
{
InitializeComponent();
}

private void Form1_Load(object sender, EventArgs e)
{
string URL = @"http://files.cnblogs.com/mossan/Zhongwen.rar";
int n = URL.LastIndexOf('/');
string fileName = URL.Substring(n + 1, URL.Length - n - 1);

if (!(Directory.Exists(Application.StartupPath + "\\update")))
{
Directory.CreateDirectory(Application.StartupPath + "\\update");
}

try 
{
update.DownloadFile(URL, Application.StartupPath +
"\\update\\" + fileName);
}
catch (WebException ex) { MessageBox.Show(ex.Message, "Error"); }

try 
{
Process UnWinrar = new Process();
UnWinrar.StartInfo.FileName = "WinRAR.exe";
UnWinrar.StartInfo.Arguments = "e -o+ \"" + Application.StartupPath +
"\\update\\" + fileName + "\"" + " \"" + Application.StartupPath +
"\\update" + "\"";
UnWinrar.Start();
MessageBox.Show("解壓縮完成!");
File.Copy(Application.StartupPath + "\\update\\" +
"Zhongwen.exe", Application.StartupPath + "\\Zhongwen.exe", true);

Process ProZhongwen = new Process();
ProZhongwen.StartInfo.FileName = Application.StartupPath + "\\Zhongwen.exe";
ProZhongwen.Start();
}
catch (Exception ex) { MessageBox.Show(ex.Message); }
this.Close();
}
}
}
View Code

自動更新程序的設計框架

概要說明:
自動更新程序主要負責從服務器中獲取相應的更新文件,而且把這些文件下載到本地,替換現有的文件。達到修復Bug,更新功能的目的。
本文做爲更新程序的一個框架性設計,主要側重介紹功能和流程。也許在若干年後,我再回顧當初本身的設計,會有另一份所獲。
 
系統組成:
FTP服務器 主要存放要更新的全部文件。提供客戶端下載
更新文件生成功能 根據FTP文件夾中的內容,生成更新列表(xml文件)
自動更新程序 判斷版本號,下載最新的文件,替換現有程序。
 
服務端的流程圖:
 
 

 
客戶端的流程圖:
 
 



更新列表文件介紹:
 
 

 
 
補充:
1:更新程序沒有作成全自動。用戶必須手工點擊更新按鈕,才啓動更新程序。
由於目前的系統平時更新並不頻繁。在系統剛上線的時候,可能更新會勤一些,但在系統運行穩定後,也許一年半載都不會去更新。
 
2:更新程序若是執行到一半,發生意外致使更新被迫終止,目前的解決方案是讓用戶再從新更新一次。沒有斷電續傳。沒有中間過程恢復。
若是更新程序使用並不頻繁,就不必加入過多的邏輯。偶爾出一些錯誤,只要不影響業務程序運行,絕大數用戶仍是能夠忍受的。
 
 3:雖然此更新功能和windows的update,瑞星的update相比,簡直就是一個小兒科程序,可是這個程序的卻也知足了我參與的全部項目的要求。
不求最好,夠用就行。呵呵
 
View Code
相關文章
相關標籤/搜索