如何让我的 C# 应用程序检查更新?

38
我正在构建一个C# Windows应用程序。 我希望每当我在我的表单中点击更新按钮时,应用程序都会在我的服务器上查找可用的新版本。
如果有,则继续更新软件。
通常如何处理这种情况?
6个回答

22

2
ClickOnce有一个主要缺点-在启动您自己的应用程序之前,它会弹出自己的窗口,这对于首次使用者来说既难看又令人困惑。它应该像Firefox或Reflector一样工作... - Krzysztof Kozmic
我看到你可以改变这种行为,例如在这里:http://bloggingabout.net/blogs/dennis/archive/2007/11/05/manual-check-for-updates-with-clickonce.aspx。 - Lennaert
3
@Krzysztof,这并不需要这样做。这完全取决于您如何配置和构建更新解决方案。您可以将所有ClickOnce交互都写在应用程序内部,而无需使用框架提供的对话框。 - J. Steen
第一个链接已经失效。 - piegames

14
让我先说一下我们提供的完整更新解决方案,其中包括:

wyUpdate处理所有Vista / Windows 7 UAC问题以及在尝试更新复杂软件时必然出现的所有文件权限问题。

话虽如此,如果您想构建自己的更新程序,以下是一些提示:

构建自己的更新程序

一个好的起点是上面提到的wyUpdate C#源代码。您可以拆卸它并将其用于自己的目的。它包含的一些算法:

  • 完全支持Windows Vista / Windows 7 UAC
  • 有限用户可以检查,然后在拥有凭据时进行更新
  • 支持奇怪的企业互联网。(如果您曾经与企业合作过,这是一个真正的问题)。
  • 快速提取、打补丁和安装文件。
  • 注册表支持。
  • 在用户出错或取消时回滚文件和注册表
  • 自我更新(不留下任何文件)

我们这里也有文件规格

自动更新

由于自动更新是必需的,让我告诉您我们如何使用我们的AutomaticUpdater控件进行自动更新。

我们使用命名管道在独立的updater(wyUpdate)和坐落在程序窗体上的自动更新控件之间进行通信。wyUpdate向自动更新器报告进度,而自动更新器可以告诉wyUpdate取消进度,开始下载、开始提取等操作。

这使得更新程序与您的应用程序分离。

事实上,我们使用的确切命名管道C#代码包含在我写的一篇文章中:类似谷歌Chrome的多进程C#应用程序


2
我可以保证wyBuild和wyUpdate是一款优秀的产品。它比ClickOnce更加灵活,而且价格非常实惠——软件工程的一个重要方面就是要知道何时购买何时构建,对我来说,这是一个明确的购买决策。 - Mark Rushakoff
1
看着这些产品,它们看起来非常棒。我只能希望有一天能够使用它们。 :) - Jake Berger
我们为开源项目和学校赞助的学生项目提供免费许可证。请参见:http://wyday.com/wybuild/buy/special-prices.php - Wyatt O'Day

11

如果你希望你的应用程序可以从网站自动更新并且由自己管理代码,请按以下步骤操作:

  1. 创建一个XML文件,例如help.xml并建立一种结构来指定要在特定目录中更新的文件列表和版本等。然后将它们上传到你的网站上。

  2. 应用程序连接到网站后会下载此help.xml文件并读取内容以确保网站上是否有任何新文件(更新文件)...

  3. 如果存在新版本的文件,则开始从help.xml文件中指定的URL下载!


4

其他答案看起来很好。

然而,如果因为任何原因你想要自己手动制作更新器,只需在web服务器上放置一个包含更新过程所需信息的XML文件(例如当前可用版本的描述和版本号),并使用HttpWebRequest(或HttpWebClient?)下载此文件并像处理任何XML文件一样进行处理。

我在peSHIr Tweets中使用这种简单的方法,效果很好。只需在提供新版本进行下载后更新此文件,您的更新检查将发现它。关于此过程的任何内容都可以按照您自己的方式进行更改,因为是您自己编写的。

除非这是为自己的娱乐/使用/学习而进行的私人项目-就像在我的情况下一样-不过还是要看看是否已经有适合您需要的内容可用!


如果有大量用户请求相同的文件,例如:100个用户运行程序,在启动时每个程序发送100个请求(版本检查),这会使标准共享托管服务器挂起吗? - techno
就像我所写的那样:对于简单的东西,你可以自己编写。这也意味着你必须自己考虑可能出现什么问题,你希望在那种情况下发生什么以及是否要为此采取措施。我只是告诉你我在我的小众应用程序中使用的内容,有几百个用户... - peSHIr

1

请看这个链接:更新检查器,我编写了它以展示在C#中实现此功能的简单方法。

这个XML文件管理着更新:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<myCoolApp>
    <currentVersion>
        <major>9</major>
        <minor>1</minor>
        <build>5</build>
    </currentVersion>
    <path>http://TestApp.exe</path>
</myCoolApp>

主要功能Check4Update()读取XML文件并解析它:
XmlDocument oDom = new XmlDocument();
oDom.Load(_sXmlConfig);

string str = oDom.SelectSingleNode("//currentVersion/major").InnerText;
Int32.TryParse(str, out _nMajor);

str = oDom.SelectSingleNode("//currentVersion/minor").InnerText;
Int32.TryParse(str, out _nMinor);

str = oDom.SelectSingleNode("//currentVersion/build").InnerText;
Int32.TryParse(str, out _nBuild); 

_sNewVersionPath = oDom.SelectSingleNode("//path").InnerText;

非常干净简单易用。注意:它不会自动下载和安装应用程序,这为客户提供了选择的机会,这很好。 - Jonas

0
给你的应用程序添加更新功能就像在公园散步一样简单。按照以下步骤,我相信你一定能够实现它。
创建一个常规文本文件,其中包含您的应用程序的新版本和应用程序的完整直接下载链接,然后将文本文件上传到您的服务器。以下是文本文件的示例内容:
1.2.0.0=http://www.yourserver.com/yourapp/update/appname_v1-2-0-0.exe 在表单中添加一个变量,用于存储更新下载链接。 private string download_link = null;
创建一个函数来检查更新。 public string CheckForUpdates() { /* 服务器上文本文件的直接下载链接 */ var version_file = "http://www.yourserver.com/appname/update/version.txt";
/* 用于处理的临时输出文件(位于AppData中) */ var temp_version_file = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\appname_version.txt";
/* 使用WebClient类从服务器下载文件 */ using (var webClient = new WebClient()) { try { webClient.DownloadFile(address: version_file, fileName: temp_version_file); } catch (Exception) { /* 处理异常 */ return "error"; } }
/* 检查临时文件是否已下载 */ if (File.Exists(temp_version_file)) { /* 获取文件内容并拆分为两部分 */ string[] version_data = File.ReadAllText(temp_version_file).Split('=');
/* 变量用于存储应用程序的新版本 */ string version = version_data[0];
/* 将下载链接存储在已创建的全局变量中 */ download_link = version_data[1];
/* 将应用程序的当前版本与下载文件中的版本进行比较 */ if (Application.ProductVersion.ToString() == version) { return "updated"; } else { return "needs_update"; } }
/* 使用完后删除临时文件 */ if (File.Exists(temp_version_file)) { File.Delete(temp_version_file); } }
创建另一个函数来执行检查(使用async-await)。 public async void RunUpdateCheck() { /* 可以向用户显示一条消息 */ labelUpdateState.Text = "正在检查更新,请稍候...";
/* 从检查函数中获取结果的变量 */ string result = await Task.Run(() => CheckForUpdates());
/* 评估结果 */ switch (result) { case "error": /* 在此处执行某些操作,可能只是通知用户 */ break;
case "updated": /* 在此处执行某些操作,可能只是通知用户 */ break;
case "needs_update": /* 执行更新操作,可能只是使用任何已安装的浏览器下载新版本, * 或者实现带有进度条等功能的下载函数,这取决于您的选择。 * * 示例: */ Process.Start(download_link); break; }
/* (可选) * 将'download_link'变量设置为null以备将来使用。 */ download_link = null;
/* (可选 - 如果您有备份功能) * 告诉用户在安装新版本之前备份可能保存的任何数据, * 如果数据存储在应用程序安装文件夹中,我建议使用AppData文件夹保存用户数据。 */ labelUpdateState.Text = "请在安装新版本之前备份您的数据"; }
我为自己开发了这种方法,而且效果非常好。你只需要在每次更新应用程序时编辑服务器上的文本文件,将应用程序版本更改为新版本。如果需要的话,还可以更改下载链接。
希望这对你们有所帮助,祝大家编码愉快!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接