ClickOnce手动更新仍然要求更新

问题描述 投票:5回答:1

我通过取消选中发布属性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 ...>
visual-studio-2017 clickonce
1个回答
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;
    }

UPDATE

另一种解决方法:

您可以创建自己的“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; }
}
© www.soinside.com 2019 - 2024. All rights reserved.