使用 Webclient 实现应用自动更新 已翻译 100%

oschina 投递于 2014/09/18 07:08 (共 6 段, 翻译完成于 09-19)
阅读 5227
收藏 92
C#
2
加载中

简介

本文提供了一个通过URL下载文件的简易实现。

背景

很多应用都会提供一个自动更新的功能,这样终端用户能获得最好的用户体验。简单地说,自动更新可以通过两步完成:

  • Step 1: 访问程序的服务端来检查是否有可用的新版本。

  • Step 2: 询问用户是否要更新并遵从用户的选择。

本文主要会讲解围绕上面两步所展开的工作流程。这是我的实际工作经验。如果您有什么疑问可以给我留言。

pseudo
翻译于 2014/09/19 09:16
1

代码

1.从服务器取得最新版本信息.

通常应用会有一个像1.20.11这样的版本号,这是一个通过'.'分隔的一系列数字。当检查服务器上的最新版本是否比用户的当前版本新时,使用版本号是一个很不错的方法。通常我们会认为1.20.22的版本要比1.20.11的版本新。

[Update]

CurrentVersion = 1.10.12

IniPath = ftp://192.168.29.19//Version.ini

此处有两个数据行。"CurrentVersion"代表了当前(用户)的应用版本,"IniPath"代表了服务器的Version.ini文件路径。我们可以下载这个Version.ini文件并读取它的版本号来做对比,这样就可以检查是否需要通知用户(是否要更新应用)。

pseudo
翻译于 2014/09/19 09:33
1

服务端的Version.ini内容:

[Update]

CurrentVersion = 1.11.00

ExePath = ............

第一个数据行表示了服务器上的应用的最新版本号,第二行代表了新版本应用的下载路径。

稍后我们会介绍如何下载这个文件,现在我先介绍如何比较两个版本号:

/** 
     *  
     * @param version1 
     * @param version2 
     * @return if version1 > version2, return 1, if equal, return 0, else return -1 
     */  
    public static int compare(String version1, String version2)
    {  
        if (version1 == null || version1.Length == 0 || version2 == null || version2.Length == 0 )
        {
            return -1;
        } 
        int index1 = 0;  
        int index2 = 0;  
        while(index1 < version1.Length && index2 < version2.Length)
        {  
            int[] number1 = getValue(version1, index1);  
            int[] number2 = getValue(version2, index2);  
              
            if (number1[0] < number2[0]) return -1;  
            else if (number1[0] > number2[0]) return 1;  
            else 
            {  
                index1 = number1[1] + 1;  
                index2 = number2[1] + 1;  
            }             
        }  
        if(index1 == version1.Length && index2 == version2.Length) return 0;  
        if(index1 < version1.Length)   
            return 1;  
        else  
            return -1;  
    }  
     /** 
     *  
     * @param version 
     * @param index the starting point 
     * @return the number between two dots, and the index of the dot 
     */  
    public static int[] getValue(string version, int index) 
    {  
        int[] value_index = new int[2];  
        StringBuilder sb = new StringBuilder();  
        while(index < version.Length && version.ElementAt(index) != &apos;.&apos;) 
        {  
            sb.Append(version.ElementAt(index));  
            index++;  
        }  
        value_index[0] = Convert.ToInt32(sb.ToString(),10); 
        value_index[1] = index;  
          
        return value_index;  
    }

这段代码通过'.'字符来分隔version字符串,然后对取得的数字依次进行比较.

(译者注:

本人觉得这个方法太过繁琐,如果使用android应用的版本控制会好点:定义一个versionName和versionCode,versionName是一个字符串,它作为版本的数字序列或名称,而versionCode作为int型的版本号,查检更新的时候可以通过versionCode这个int型的数字直接比较)

pseudo
翻译于 2014/09/19 09:46
1

2. 从服务端下载文件.

正如本文标题所说,此方法会用到webclient接口来进行下载。它提供了很多用于下载的方法。

webclient提供了同步和异常方法。同步方法会阻塞线程。它通常用于下载耗时较短的小文件。在这我们使用同步方法来下载INI文件。代码如下:

// New a webclient object
    WebClient web  = new WebClient();

//Download synchronized 

try
{
     string UserName = AutoUpdate.Form1.GetStringFromFile("UpdateInfo", "ID_USER_NAME");
     string PassWord = AutoUpdate.Form1.GetStringFromFile("UpdateInfo", "ID_USER_PASSWORD");
     web.Credentials = new NetworkCredential(UserName, PassWord);
     web.DownloadFile(new Uri(ServerIniPath.ToString()), ItemSavePath);        
}
catch (System.Exception ex)
{                  
     throw ex;
}

pseudo
翻译于 2014/09/19 09:50
1

我们可以从INI文件中取得最新应用的下载路径,如果需要下载它,我们应该使用异步方法.

try
{
    web.DownloadFileAsync(new Uri(DownLoadAddress), ItemSavePath);
    web.DownloadProgressChanged += client_DownloadProgressChanged;
    web.DownloadFileCompleted += client_DownloadFileCompleted;
}
catch (System.Exception ex)
{
    throw ex;
}

从代码我们可以看到当调用下载方法后,我们也为它添加了两个事件handler(处理器)。这两个handler可以告知我们下载的详细信息,例如已下载百分比,已下载字节数等等。handler代码如下:

void client_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
   Action<AsyncCompletedEventArgs> onCompleted = progressCompleted;
   onCompleted.Invoke(e);
}

void client_DownloadFileProgresschanged(object sender, AsyncCompletedEventArgs e)
{
   Action<DownloadProgressChangedEventArgs> onCompleted = progressChanging;
   onCompleted.Invoke(e);
}

方法progressCompleted和progressChanging可以按需实现。

pseudo
翻译于 2014/09/19 10:06
1

3. 下载异常.

这个异常并不是通过try和catch捕获的异常。这是一个真正的异常:网络不可用,用户取消更新,服务器不可用。因为我们使用异步方法进行下载,这会导致很多并发问题。接下来我会介绍我是如何处理它们的。

网络不可用.

这个问题随时都会发生,所以我需要启用另一个线程,它会根据时间来检查网络状态。一旦发现网络断开了,我会调用下载线程来通知用户。

如何检查网络状态其实很简单,我们可以使用 "wininet.dll"提供的方法。

[DllImport("wininet.dll")]
  public static extern bool InternetGetConnectedState(out int lpdwFlags, int dwReserved);

用户取消下载:

weblient已经考滤到了这种情况,它提供了cancel方法来停止下载和dispose方法释放下载进程占用的资源。

结束.

pseudo
翻译于 2014/09/19 10:22
1
本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接。
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。
加载中

评论(5)

当当
文中有说和android有关系?
Micooz
Micooz
卧槽这不是C#吗?和android有何关系?
哈哈爱兮爱兮乎乎
能穿防火墙么
王洪旭
王洪旭
mark
ahanle
ahanle
Wee
返回顶部
顶部