Как обновить сборку для запущенного процесса c # (AKA hot deploy)? - PullRequest
12 голосов
/ 25 февраля 2010

У меня есть сборка .exe и набор ссылочных сборок, для которых я хотел бы иметь возможность развертывать обновленный код. На самом деле мне не нужно менять исполняемый код, но при следующем запуске исполняемого файла я бы хотел, чтобы он взял обновленный код. В настоящее время, когда я пытаюсь скопировать запущенный файл, я получаю сообщение об ошибке .exe, который используется другим процессом.

Подводя итог; как я могу обновить код, пока используется .exe?

Ответы [ 8 ]

18 голосов
/ 25 февраля 2010

Это легко сделать. Вы можете переименовать файл, Windows имеет блокировку на ручке, а не запись каталога для файла. Теперь вы можете просто скопировать обновление без проблем. Осталось только избавиться от переименованного файла после повторного запуска приложения. При необходимости.

3 голосов
/ 25 февраля 2010

Я не думаю, что это возможно. Например, при развертывании приложений asp.net с нулевым временем простоя рекомендуется использовать балансировщик нагрузки, чтобы можно было отключить один экземпляр, обновить его, а затем удалить другой для обновления.

2 голосов
/ 08 января 2012

Этот класс переименует исполняемый в данный момент исполняемый файл, если он завершается без исключения, вы можете просто написать новый исполняемый файл, а затем перезапустить, например:

Ourself.Rename();
// Download or copy new version
File.Copy(newVersion, Ourself.FileName());
// Launch new version
System.Diagnostics.Process.Start(Ourself.FileName());
// Close current version
Close(); // Exit();

Достаточно просто?

class Ourself
{
    public static string FileName() {
        Assembly _objParentAssembly;

        if (Assembly.GetEntryAssembly() == null)
            _objParentAssembly = Assembly.GetCallingAssembly();
        else
            _objParentAssembly = Assembly.GetEntryAssembly();

        if (_objParentAssembly.CodeBase.StartsWith("http://"))
            throw new IOException("Deployed from URL");

        if (File.Exists(_objParentAssembly.Location))
            return _objParentAssembly.Location;
        if (File.Exists(System.AppDomain.CurrentDomain.BaseDirectory + System.AppDomain.CurrentDomain.FriendlyName))
            return System.AppDomain.CurrentDomain.BaseDirectory + System.AppDomain.CurrentDomain.FriendlyName;
        if (File.Exists(Assembly.GetExecutingAssembly().Location))
            return Assembly.GetExecutingAssembly().Location;

        throw new IOException("Assembly not found");
    }

    public static bool Rename()
    {
        string currentName = FileName();
        string newName = FileName() + ".ori";
        if (File.Exists(newName))
        {
            File.Delete(newName);
        }
        File.Move(currentName, newName);
        return true;
    }
}
2 голосов
/ 25 февраля 2010

ClickOnce дает вам несколько вариантов. Существует стратегия обновления «обновление после запуска приложения».

Для более сложных сценариев существует пространство имен System.Deployment . Например, вы можете периодически запрашивать обновления в вашем приложении.

2 голосов
/ 25 февраля 2010

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

Таким образом, когда пользователь запускает программу, вы можете выполнять теневое копирование (локально) с сайта развертывания, которое всегда можно перезаписать.

1 голос
/ 25 февраля 2010

Лучшей идеей будет один из предложенных ответов ... например, использование перекомпоновки с MEF и ClickOnce. Тем не менее, эти решения не помогут вам для «этого развертывания». Они требуют, чтобы вы внесли изменения в исполняемый файл и / или создали исполняемый файл загрузочного ремешка, который поможет вам только при следующем развертывании.

Для этого развертывания вы можете попробовать сделать это (я никогда не делал этого раньше, но теоретически это могло бы работать):

  1. Скопируйте ваши новые DLL в подпапку куда-нибудь
  2. Добавьте команду xcopy для командной строки в ключ реестра RunOnce , чтобы скопировать новый dll из подпапки в конечную папку exe, куда вы хотите, чтобы он пошел.
  3. Reboot.

Ключ RunOnce содержит команды командной строки, которые запускаются один раз при перезагрузке, а затем удаляются из реестра, чтобы они больше не запускались. Вот как InstallShield позволяет перезаписывать определенные библиотеки DLL, когда они используются другими приложениями.

1 голос
/ 25 февраля 2010

А как насчет следующего:

  1. Разверните exe-файл в папку обновления.
  2. Когда приложение запускается, оно проверьте папку обновления.
  3. Если оно не пустое, выполнить копию Программа
  4. Затем программа копирования заменит существующий exe с тем в папка обновления
  5. Удалить что-нибудь в папке обновлений
  6. Затем перезапустите exe
1 голос
/ 25 февраля 2010

Просто идея: попробуйте MEF и [Import ["http://someRemoteResource"]]

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...