.net程序如何自行更新?

时间:2009-10-22 21:08:26

标签: .net

我已经编写了一个程序,如果它在服务器上找到更新的版本就会更新自己,但我发现很难干净地实现它。

检查远程服务器并下载文件很简单但是那又如何呢?它不能简单地File.Copy(“newversion.exe”,“myprogram.exe”),因为myprogram正在运行且文件被锁定。

我是通过下载两个文件newversion和更新来实现的。 myprogram然后启动更新并退出。 更新等待两秒钟,复制,然后启动myprogram(现在是更新版本)并退出。 myprogram在启动时查找更新并删除它,如果找到则返回newversion。 mypogram现在是新版本,没有留下文件。

必须有一种比这更好的方法,那么程序更新自己的.net方式是什么?

PS。很抱歉,如果这个问题出现两次 - 我第一次提交时会出现'堆栈溢出已损坏'页面。

5 个答案:

答案 0 :(得分:15)

查看ClickOnce Deployment是否能满足您的需求。

答案 1 :(得分:7)

我看了Wix和ClickOnce并且不喜欢他们。对于单文件“xcopy部署”类型的WPF应用程序,我想要更简单的东西。

所以我建了一个。这是一个AppUpdater类,您可以将其放入任何WPF应用程序中,并在必要时自动更新。

检查版本号并下载最新版本很容易。

下一部分不太容易。你如何替换正在运行的应用程序?我采取的方法是:

  • 每次运行时,应用程序都会检查一个众所周知的URL版本。如果版本不晚于当前正在执行的应用程序的版本,则没有其他任何事情要做。

  • 如果以后版本为IS,那么app会抓取一个名为Mutex,将自身(Assembly.GetExecutingAssembly()。Location)复制到临时位置,然后从该临时位置启动一个新进程(进程#2) ,传递一个命令行参数,说明“你正在尝试更新”并给出原始的exe位置。

  • 进程#1自行关闭。

  • 进程#2启动 - 它看到它正在尝试更新,因此它会下载更新的图像,并将其放在原始位置(在命令行上传递的位置)。它不是等待2秒或任何任意时间,而是使用命名的互斥锁来确定进程#1何时退出。

  • 进程#2然后使用原始位置启动进程#3。

  • 进程#2关闭,释放其名为Mutex。

  • 进程#3启动。它会检查版本URL - 看到它是最新的。无需更新。进程#3还等待进程#2释放其Mutex,然后删除EXE的临时副本 - 进程#2使用的临时副本。


修改

回应评论,是的,这听起来很复杂。但是AppUpdater模块中所有这一切的逻辑。从WPF应用程序中使用它非常简单:

public partial class Window1 : Window
{
    public Window1()
    {
        InitializeComponent();
        // add this line in your constructor
        if (UpdaterCheck())  this.Hide();
    }

    // this is all boilerplate
    private Ionic.AppUpdater.Wpf.Updater _updater;
    private string _manifestUrl = "http://example.org/AppUpdates/MyApplication/Manifest.xml";
    private string _infoUrl     = "http://example.org/MyApplication.html";
    private string _description = "MyApplication is a delightful application; it does x, y, and z. ";
    // Obtain the publicKey XML from the ManifestTool that ships with Ionic AppUpdater.
    // The following string is Ionic's public key.  You will need a different one.
    // Consult the Readme for more information.
    private string _publicKeyXml = "<RSAKeyValue><Modulus>sZqhvF0KX6m4blah..blah...=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>";

    // add this boilerplate method
    private bool UpdaterCheck()
    {
        _updater = new Ionic.AppUpdater.Wpf.Updater("This is MyApplication.",
                                                    _infoUrl,
                                                    _description,
                                                    _manifestUrl,
                                                    _publicKeyXml);
        return _updater.Status.IsUpdating;
     }
    ...

Details and code you can run, here

它仅适用于WPF应用程序,但构建WinForms版本的东西非常简单。同样的想法,虽然生成UI的一些逻辑必须改变。

答案 2 :(得分:3)

您可以使用WIXClickOnce。他们为你处理它。

答案 3 :(得分:2)

当你知道“解决方法”时很容易。您的程序无法自行下载,因为该文件已被正在运行的进程锁定。解决方法是仍然可以重命名该文件。所以这就是你做的:

如果您的程序名称是“myprogram.exe”:

  1. myprogram.exe启动
  2. Myprogram.exe下载了自己的新版本,但名称为“newversion.bak”
  3. 检查newversion.bak是否已下载正确(md5-check或其他)
  4. myprogram.exe将“myprogram.exe”重命名为“myprogram.old”
  5. myprogram.exe将“newversion.bak”重命名为“myprogram.exe”
  6. myprogram.exe重新启动,瞧,更新了。
  7. (可选)myprogram.exe在启动时删除“myprogram.old”。
  8. 这将允许您在没有外部更新程序的情况下更新程序。

答案 4 :(得分:0)

您可能需要查看.NET's No Touch Deployment。它至少在市场营销中被Click-Once取代。

我写了一个使用它的应用程序。它从本地Intranet服务器中取出了它的程序集。它使用套接字来侦听特定端口,因此我可以通过发送消息来强制升级,这会生成另一个程序来杀死它/重新启动它。可能不是最好的解决方案,但它有效。

我说Click-Once是一个更好的解决方案,但我想我会提到No Touch。