Как можно обновить программу .net?

Я написал программу, которая обновляет себя, если находит более новую версию на сервере, но мне сложно выполнить ее чисто.

Проверка удаленного сервера и загрузка файла достаточно просты, но что? Он не может просто File.Copy( "newversion.exe", "myprogram.exe" ), потому что моя программа запущена и файл заблокирован.

Я делаю это, загружая два файла newversion и update. Затем myprogram запускает обновление и завершает работу. обновление ждет две секунды, выполняет ли копирование, затем запускает myprogram (которая теперь является обновленной версией) и выходит. myprogram ищет обновление при запуске и удаляет его и newversion, если он их находит. mypogram теперь является новой версией без файлов, оставшихся на месте.

Должен быть лучший способ, чем это, а что .net-путь для самой программы для обновления?

PS. Извините, если этот вопрос появляется дважды - в первый раз, когда я отправил его, у меня была страница с переполнением стека.

Ответы

Ответ 1

Смотрите, если ClickOnce Deployment дает вам то, что вам нужно.

Ответ 2

Я посмотрел как на Wix, так и на ClickOnce и не любил их. Я хотел что-то более простое, для однофайловых приложений WPF типа xcopy для развертывания.

Итак, я построил один. Это класс AppUpdater, который вы можете загрузить в любое приложение WPF, автоматически обновляя его при необходимости.

Проверка номера версии и загрузка последней версии легко.

Следующая часть менее проста. Как заменить запущенное приложение? Подход, который я принял, был следующим:

  • каждый раз, когда он запускается, приложение проверяет известный URL-адрес для версии. Если версия не позднее версии исполняемого приложения, то больше делать нечего.

  • Если версия позже, приложение захватывает именованный Mutex, копирует себя (Assembly.GetExecutingAssembly(). Location) во временное место, а затем запускает новый процесс (процесс № 2) из ​​этого временного местоположения, передавая аргумент командной строки, который говорит "вы пытаетесь обновить" и даете исходное местоположение exe.

  • процесс № 1 отключается.

  • процесс № 2 запускается - он видит, что он пытается обновить, поэтому он загружает обновленное изображение и помещает его в исходное местоположение (место, которое было передано в командной строке). Вместо того, чтобы ждать 2 секунды или любое произвольное время, он использует именованный Mutex, чтобы определить, когда завершился процесс №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 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;
     }
    ...

Подробности и код, который вы можете запустить здесь.

Он работает только с приложениями WPF, но было бы довольно просто создать версию WinForms. Такая же идея, хотя какая-то логика, которая генерирует пользовательский интерфейс, должна измениться.

Ответ 3

Вы можете использовать WIX или ClickOnce. Они справляются с этим для вас.

Ответ 4

Легко, когда вы знаете "обходной путь". Ваша программа не может загрузиться сама по себе, потому что файл заблокирован запущенным процессом. Обходной путь заключается в том, что все еще возможно RENAME файл. Итак, вот что вы делаете:

Если ваше имя программы "myprogram.exe" :

  • myprogram.exe запускает
  • Myprogram.exe загружает новую версию, но под названием "newversion.bak"
  • Убедитесь, что newversion.bak скачал правильно (md5-check или что-то еще)
  • myprogram.exe переименовывает "myprogram.exe" в "myprogram.old"
  • myprogram.exe переименовывает "newversion.bak" в "myprogram.exe"
  • myprogram.exe перезапускает себя, а voila - обновляется.
  • (необязательно) myprogram.exe удаляет "myprogram.old", если существует при запуске.

Это позволит вам обновить вашу программу без внешнего обновления.

Ответ 5

Вы можете посмотреть .NET No Touch Deployment. Он был заменен, по крайней мере, маркетингом Click-Once.

Я написал приложение, которое использовало это. Он вытащил сборку с локального сервера интрасети. Он использовал сокеты для прослушивания определенного порта, поэтому я смог принудительно обновить их, отправив сообщение, которое породило другую программу, чтобы убить ее/перезапустить. Вероятно, это не лучшее решение, но оно сработало.

Я бы сказал, что Click-Once - лучшее решение, но я думал, что упоминаю No Touch.