我如何回滚一个ClickOnce应用程序?

有没有一种方法(hacky会这样做),以允许用户返回ClickOncenetworking已部署应用程序的先前版本?

我看了文档和API,似乎没有办法。 你可以有select地select是否要更新,但一旦更新,似乎没有回头路。

ClickOnce将使用您发送的任何版本。 如果您发送一个旧版本,他们将回滚到旧版本。

早在五月份,我的好友大卫写了一篇关于如何在每个用户的基础上这样做的文章。 我们可以从字面上让每个用户使用不同的版本。 应用程序甚至会告诉数据库用户需要哪个版本,所以他们理论上可以改变他们的版本,然后重启应用程序。

使用ClickOnce进行细粒度的版本控制

您可以通过更改服务器清单文件来恢复到服务器端的旧版本。 当客户端重新启动应用程序时,它会看到它的版本与服务器所说的是“当前”版本不同,它会下载新的版本。 这个服务器清单文件通常总是指向最新的版本,但并不是必须的。

以下是如何更改它(我使用Visual Studio 2008发布的。其他版本可能有不同的发布文件夹结构)。

在与publish.htm相同的文件夹中,是名为[appName].application的XML文档。 这是客户端用来比较其当前版本的服务器端清单文件。 包含在本文档中的包括客户端应该运行的“当前”版本以及服务器上可以find部署文件的位置。

在与publish.htm相同的位置也是一个名为“应用程序文件”的文件夹。 此文件夹包含以前每个发布的子文件夹。 在这些子文件夹中的每一个都是另一个与我上面提到的名称相同的XML文档,称为[appName].application 。 复制这个文件(从包含你想恢复的版本的任何文件夹中)并粘贴到与publish.htm (几个级别)相同的文件夹中。 当客户端应用程序重新启动时,它就会像新版本一样可用,下载并运行它。 客户端现在将运行以前的版本。

你可以进入添加/删除应用程序并select你的应用程序,并select最后的安装。

您可以使用MAGEUI回滚到服务器上以前的清单版本。 看看这个 。

如果查看部署位置,则会看到每个以前的版本,在附加了版本号的单独文件夹中,以及部署清单(也附加了版本号)。

您可以将其中的任何一个重命名为当前的部署,并且在您下次更新该应用程序时,它将提取您回滚的版本。

我明白ClickOnce版本检查algorythm如下:

  1. 如果安装在客户端上的版本=版本部署到服务器 – 什么也不做
  2. 如果客户端版本<服务器版本 – 升级
  3. 如果客户端版本>服务器版本:
    1. 如果在客户端> =服务器版本上指定了minimumVersion,则显示错误
    2. 如果在客户端<服务器版本上指定了minimumVersion – 降级
    3. 如果客户机上没有指定minimumVersion – 降级

如果您知道发布者URI和部署和应用程序的名称,版本语言公钥标记和处理器体系结构,则可以通过reflection来完成。

下面的代码将尝试回滚“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 }); } } } } 

我只需要在我的现场制作服务器上完成其中的一个,并且很高兴有这些笔记。 我的解决scheme有点不同,我想补充一点。 在进行生产部署之前,我总是事先备份整个包含的文件夹。 我能够将我的整个文件夹结构复制回原来的状态,一切正常。

注意这个方法的注意事项:

  • 如果应用程序很大,或者应用程序文件夹中已经发布了很多版本,则备份将会很大。 确保你有足够的空间(对于我来说存储是没有对象的)。
  • 权限有这样一个咬你的恶毒的倾向。 确保您的部署位置是否承载了外部访问,以便在恢复之前和之后validation所有权限。
  • 在IIS中回收我的应用程序池对我很有帮助。