Как я могу откатить приложение ClickOnce? - PullRequest
47 голосов
/ 14 октября 2008

Есть ли способ (хакки подойдет), чтобы позволить пользователю вернуться к предыдущей версии ClickOnce сетевого приложения?

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

Ответы [ 9 ]

83 голосов
/ 03 ноября 2009

Вы можете вернуться к более старой версии на стороне сервера, изменив файл манифеста сервера. Когда клиент перезапустит приложение, он увидит, что у него другая версия, чем то, что сервер называет «текущей» версией, и он загрузит новую. Этот файл манифеста сервера обычно всегда указывает на самую последнюю версию, но это не обязательно.

Вот как это можно изменить (я публиковал с помощью Visual Studio 2008. Другие версии могут иметь другую структуру папок публикации).

В той же папке, что и publish.htm, находится документ XML с именем [appName].application. Это файл манифеста на стороне сервера, с которым клиент сравнивает свою текущую версию. В этом документе содержится «текущая» версия, в которой должен работать клиент, а также местоположение на сервере, где можно найти файлы развертывания.

В том же месте, что и publish.htm, также находится папка «Файлы приложений». Эта папка содержит подпапки для каждой из предыдущих публикаций. В каждой из этих подпапок находится другой XML-документ с тем же именем, которое я упомянул выше, и называется [appName].application. Скопируйте этот файл (из любой папки, содержащей версию, в которую вы хотите вернуться) и вставьте ее в ту же папку, что и publish.htm (на несколько уровней выше). Когда клиентское приложение перезапускается, оно будет выглядеть так же, как новая версия, загрузите ее и запустите. Теперь клиент будет использовать предыдущую версию.

18 голосов
/ 14 октября 2008

ClickOnce будет использовать любую версию, которую вы им отправите. Если вы отправите им старую версию, они вернутся к этой старой версии.

Еще в мае мой приятель Дэвид написал статью о том, как сделать это для каждого пользователя. Мы можем буквально иметь каждого пользователя в другой версии. Приложение даже сообщает базе данных, какую версию хочет пользователь, поэтому теоретически они могут изменить свою версию и затем просто перезапустить приложение.

Мелкозернистая версия с ClickOnce

8 голосов
/ 14 октября 2008

Вы можете зайти в «Добавить / Удалить приложение», выбрать свое приложение и выбрать вместо него получить последнюю установку.

2 голосов
/ 14 октября 2008

Вы можете использовать MAGEUI для отката к предыдущей версии манифеста на сервере. Проверьте это .

1 голос
/ 24 сентября 2013

Я понимаю алгоритм проверки версии ClickOnce следующим образом:

  1. Если версия установлена ​​на клиенте = версия развернута на сервере - ничего не делать
  2. Если версия клиента <версия сервера - обновить </li>
  3. Если версия клиента> версия сервера:
    1. Если минимальная версия указана на клиенте> = версия сервера - показать ошибку, как у нас
    2. Если минимальная версия указана на клиенте <версия сервера - понижение </li>
    3. Если минимальная версия не указана на клиенте - понижение
1 голос
/ 14 октября 2008

Если посмотреть на местоположение развертывания, вы увидите каждую предыдущую версию в отдельной папке с добавленным номером версии, а также с манифестом развертывания, также с добавленным номером версии.

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

0 голосов
/ 29 ноября 2018

Просто использовал это для отката приложения clickonce, разработанного в Visual Studio 2017. В моем случае в корневой папке было всего два файла; один называется [applicationName] .manifest, другой setup.exe.

[applicationName] .manifest содержал числовые ссылки на номер текущей версии, но каждая из них была связана со значением publicKeyToken, поэтому я неохотно редактировал его вручную.

Итак, в папке «Файлы приложения», в подпапке с версией, которую я хотел откатить, я обнаружил еще один [applicationName] .manifest, который я скопировал в корневую папку (сделав резервную копию оригинала).

И это было все. Это сработало для меня и было действительно простым решением. Однако я не использую минимально требуемую версию, поэтому не могу сказать, повлияет ли это на нее.

0 голосов
/ 28 июня 2012

Это можно сделать с помощью рефлексии, если вы знаете издателя URI и имя, маркер открытого ключа языка версии и архитектуру процессора как развертывания, так и приложения.

Приведенный ниже код попытается откатить приложение «coolapp.app» ClickOnce . Если он не может выполнить откат, он попытается удалить его.

using System;
using System.Deployment.Application;
using System.Reflection;

namespace ClickOnceAppRollback
{
    static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        static void Main()
        {
            string appId = string.Format("{0}#{1}, Version={2}, Culture={3}, PublicKeyToken={4}, processorArchitecture={5}/{6}, Version={7}, Culture={8}, PublicKeyToken={9}, processorArchitecture={10}, type={11}",
                /*The URI location of the app*/@"http://www.microsoft.com/coolapp.exe.application",
                /*The application's assemblyIdentity name*/"coolapp.app",
                /*The application's assemblyIdentity version*/"10.8.62.17109",
                /*The application's assemblyIdentity language*/"neutral",
                /*The application's assemblyIdentity public Key Token*/"0000000000000000",
                /*The application's assemblyIdentity processor architecture*/"msil",
                /*The deployment's dependentAssembly name*/"coolapp.exe",
                /*The deployment's dependentAssembly version*/"10.8.62.17109",
                /*The deployment's dependentAssembly language*/"neutral",
                /*The deployment's dependentAssembly public Key Token*/"0000000000000000",
                /*The deployment's dependentAssembly processor architecture*/"msil",
                /*The deployment's dependentAssembly type*/"win32");

            var ctor = typeof(ApplicationDeployment).GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, new Type[] { typeof(string) }, null);
            var appDeployment = ctor.Invoke(new object[] { appId });

            var subState = appDeployment.GetType().GetField("_subState", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(appDeployment);
            var subStore = appDeployment.GetType().GetField("_subStore", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(appDeployment);
            try
            {
                subStore.GetType().GetMethod("RollbackSubscription").Invoke(subStore, new object[] { subState });
            }
            catch
            {
                subStore.GetType().GetMethod("UninstallSubscription").Invoke(subStore, new object[] { subState });
            }
        }
    }
}
0 голосов
/ 22 февраля 2012

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

Примечания предостережения с этим методом:

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