ClickOnce手动更新仍然要求更新

时间:2019-01-15 18:01:12

标签: visual-studio-2017 clickonce

我通过取消选中发布属性The application should check for updates来禁用Visual Studio中的更新检查。

我的应用检查更新,用户必须选择拒绝更新。

问题是,当用户跳过更新时,下次启动应用程序时,将再次显示默认的ClickOnce更新屏幕。

如何确保它永远不会显示默认的ClickOnce更新对话框?

我的更新代码:

private void CheckForUpdates()
{
    if (!ApplicationDeployment.IsNetworkDeployed)
    {
        return;
    }

    var currentDeployment = ApplicationDeployment.CurrentDeployment;

    UpdateCheckInfo info;
    try
    {
        info = currentDeployment.CheckForDetailedUpdate();
    }
    catch (Exception e)
    {
        return;
    }

    if (!info.UpdateAvailable)
    {
        return;
    }

    var changelogDialog = new Changelog();
    if (changelogDialog.ShowDialog() != true)
    {
        return;
    }

    currentDeployment.Update();

    Exit();
}

这是我的清单:

<?xml version="1.0" encoding="utf-8"?>
<asmv1:assembly xsi:schemaLocation="urn:schemas-microsoft-com:asm.v1 assembly.adaptive.xsd" manifestVersion="1.0" xmlns:asmv1="urn:schemas-microsoft-com:asm.v1" xmlns="urn:schemas-microsoft-com:asm.v2" xmlns:asmv2="urn:schemas-microsoft-com:asm.v2" xmlns:xrml="urn:mpeg:mpeg21:2003:01-REL-R-NS" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" xmlns:dsig="http://www.w3.org/2000/09/xmldsig#" xmlns:co.v1="urn:schemas-microsoft-com:clickonce.v1" xmlns:co.v2="urn:schemas-microsoft-com:clickonce.v2">
  <assemblyIdentity name="test.ccpl.Desktop.application" version="1.0.0.89" publicKeyToken="7613da056444d824" language="en-CA" processorArchitecture="x86" xmlns="urn:schemas-microsoft-com:asm.v1" />
  <description asmv2:publisher="test ccpl" co.v1:suiteName="test" asmv2:product="test ccpl" xmlns="urn:schemas-microsoft-com:asm.v1" />
  <deployment install="true" mapFileExtensions="true" co.v1:createDesktopShortcut="true">
    <deploymentProvider codebase="https://test-test.test.ca/Installers/test.ccpl.Desktop.application" />
  </deployment>
  <dependency>
    <dependentAssembly dependencyType="install" codebase="Application Files\test.ccpl.Desktop_1_0_0_89\test.ccpl.Desktop.exe.manifest" size="58997">
      <assemblyIdentity name="test.ccpl.Desktop.exe" version="1.0.0.89" publicKeyToken="7613da056444d824" language="en-CA" processorArchitecture="x86" type="win32" />
      <hash>
        <dsig:Transforms>
          <dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
        </dsig:Transforms>
        <dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
        <dsig:DigestValue>u36JKY4n1mmu2LZC3Ea5uRLheiM=</dsig:DigestValue>
      </hash>
    </dependentAssembly>
  </dependency>
  <compatibleFrameworks xmlns="urn:schemas-microsoft-com:clickonce.v2">
    <framework targetVersion="4.7.2" profile="Full" supportedRuntime="4.0.30319" />
  </compatibleFrameworks>
<publisherIdentity ...>

1 个答案:

答案 0 :(得分:4)

我认为您所看到的一切都是设计使然。 调用currentDeployment.CheckForDetailedUpdate()后,clickonce会将该更新元数据存储在注册表中。在下次启动时,clickonce将始终查看此信息,以查看是否有挂起的部署,如果有,则还将确定用户是否已跳过此较新版本。不管您是否愿意,这都是设计使然。

但是,如果您真的想摆脱启动时的clickonce更新对话框,那么可以使用一个丑陋的解决方案:-) 更新:请参见下面的第二种解决方法。

首先,让我们看一下注册表以及一切工作原理:

  • 导航到该位置:
    HKEY_CURRENT_USER\Software\Classes\Software\Microsoft\Windows\CurrentVersion\Deployment\SideBySide\2.0\PackageMetadata\{2ec93463-b0c3-45e1-8364-327e96aea856}_{3f471841-eef2-47d6-89c0-d028f03a4ad5}\

  • 对于每个已安装的clickonce应用程序,您将看到3个子键。 在我的情况下,该应用程序称为WindowsApplication,公共密钥令牌为a619d47505395849。因此,要查找的重要密钥始于wind..tion_a619d47505395849_

    enter image description here

  • 您应该会看到类似于 test..tion_7613da056444d824_xxxxxxxxxx 的内容。只需遍历密钥,查找公共密钥令牌并选择最短的密钥即可。

  • 现在是重要的部分。查看名称以!PendingDeployment结尾的值。调用CheckForDetailedUpdate方法后,它应如下所示:

    enter image description here enter image description here

    这就是显示“更新对话框”的原因。

  • 然后将其替换为该值即可完成

    enter image description here

  • 然后将不再显示“更新”对话框。用户可以在应用程序中手动检查更新,一次又一次接受或忽略它。

您可以手动测试这些步骤,以查看是否一切正常。将其放入代码应类似于以下内容:

    var changelogDialog = new Changelog();
    if (changelogDialog.ShowDialog() != true)
    {
        RegistryKey key = Registry.CurrentUser.OpenSubKey(@"Software\Classes\Software\Microsoft\Windows\CurrentVersion\Deployment\SideBySide\2.0\PackageMetadata\{2ec93463-b0c3-45e1-8364-327e96aea856}_{3f471841-eef2-47d6-89c0-d028f03a4ad5}");
        var subkeyName = key.GetSubKeyNames().Where(x => x.Contains("7613da056444d824")).OrderBy(x => x.Length).First();
        var subkey = key.OpenSubKey(subkeyName, true);
        subkey.SetValue("{2ad613da-6fdb-4671-af9e-18ab2e4df4d8}!PendingDeployment", new byte[] { 00, 00 }, RegistryValueKind.Binary);

        return;
    }

更新

另一种解决方法:

您可以创建自己的“ CheckForUpdate”方法,而不是调用内置函数CheckForDetailedUpdate()。没什么大不了的:

private CustomUpdateCheckInfo CheckForUpdate()
{
    var info = new CustomUpdateCheckInfo();

    var currentVersion = ApplicationDeployment.CurrentDeployment.CurrentVersion;
    var manifestUri = ApplicationDeployment.CurrentDeployment.UpdateLocation;

    using (XmlTextReader reader = new XmlTextReader(manifestUri.AbsoluteUri))
    {
        var doc = XDocument.Load(reader);
        var version = doc.Descendants().FirstOrDefault(n => n.Name.LocalName == "assemblyIdentity").Attribute("version").Value;

        info.NewestVersion = version;
        info.IsUpdateAvailable = currentVersion.ToString() != version;
    }

    return info;
}

它将比较清单文件中当前部署的版本和最新版本,并返回CustomUpdateCheckInfo的实例:

public class CustomUpdateCheckInfo
{
    public bool IsUpdateAvailable { get; set; }
    public string NewestVersion { get; set; }
}