ClickOnce部署自动更新无法正常工作。

4
我正在使用 ClickOnce 部署来检查更新:
  1. 我已经按照发布选项卡中的设置进行了设置,包括发布 URL、检查更新路径、在应用程序启动之前检查更新以及在线和离线运行应用程序。
  2. 如果从本地系统安装应用程序,则可以获取更新,但如果从服务器安装应用程序,则不会检查更新。

以下是我用于检查更新的代码。我该如何解决这个问题?

private void InstallUpdateSyncWithInfo()
{
    UpdateCheckInfo info = null;
    if (ApplicationDeployment.IsNetworkDeployed)
    {
        ApplicationDeployment ad = ApplicationDeployment.CurrentDeployment;

        try
        {
            info = ad.CheckForDetailedUpdate();
        }
        catch (DeploymentDownloadException dde)
        {
            MessageBox.Show("The new version of the application cannot be downloaded at this time. \n\nPlease check your network connection, or try again later. Error: " + dde.Message);
            return;
        }
        catch (InvalidDeploymentException ide)
        {
            MessageBox.Show("Cannot check for a new version of the application. The ClickOnce deployment is corrupt. Please redeploy the application and try again. Error: " + ide.Message);
            return;
        }
        catch (InvalidOperationException ioe)
        {
            MessageBox.Show("This application cannot be updated. It is likely not a ClickOnce application. Error: " + ioe.Message);
            return;
        }

        if (info.UpdateAvailable)
        {
            Boolean doUpdate = true;

            if (!info.IsUpdateRequired)
            {
                DialogResult dr = MessageBox.Show("An update is available. Would you like to update the application now?", "Update Available", MessageBoxButtons.OKCancel);
                if (!(DialogResult.OK == dr))
                {
                    doUpdate = false;
                }
            }
            else
            {
                // Display a message that the app MUST reboot. Display the minimum required version.
                MessageBox.Show("This application has detected a mandatory update from your current " +
                    "version to version " + info.MinimumRequiredVersion.ToString() +
                    ". The application will now install the update and restart.",
                    "Update Available", MessageBoxButtons.OK,
                    MessageBoxIcon.Information);
            }

            if (doUpdate)
            {
                try
                {
                    ad.Update();
                    MessageBox.Show("The application has been upgraded, and will now restart.");
                    Application.Restart();

                }
                catch (DeploymentDownloadException dde)
                {
                    MessageBox.Show("Cannot install the latest version of the application. \n\nPlease check your network connection, or try again later. Error: " + dde);
                    return;
                }
            }
        }
    }
    else
    {
        MessageBox.Show("There are no updates available");
    }
}

C# 项目文本文件:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build"
    xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <PropertyGroup>
        <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
        <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
        <ProductVersion>8.0.30703</ProductVersion>
        <SchemaVersion>2.0</SchemaVersion>
        <ProjectGuid>{1804771A-88C8-49AD-9763-44A296B7EC2B}</ProjectGuid>
        <OutputType>WinExe</OutputType>
        <AppDesignerFolder>Properties</AppDesignerFolder>
        <RootNamespace>TestUpdate</RootNamespace>
        <AssemblyName>TestUpdate</AssemblyName>
        <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
        <TargetFrameworkProfile>Client</TargetFrameworkProfile>
        <FileAlignment>512</FileAlignment>
        <IsWebBootstrapper>true</IsWebBootstrapper>
        <PublishUrl>C:\Program Files %28x86%29\Zend\Apache2\htdocs\TestUpdate\</PublishUrl>
        <Install>true</Install>
        <InstallFrom>Web</InstallFrom>
        <UpdateEnabled>true</UpdateEnabled>
        <UpdateMode>Foreground</UpdateMode>
        <UpdateInterval>7</UpdateInterval>
        <UpdateIntervalUnits>Days</UpdateIntervalUnits>
        <UpdatePeriodically>false</UpdatePeriodically>
        <UpdateRequired>true</UpdateRequired>
        <MapFileExtensions>true</MapFileExtensions>
        <InstallUrl>http://www.acharis.com/Clinic/TestUpdate/</InstallUrl>
        <UpdateUrl>http://www.acharis.com/Clinic/TestUpdate/</UpdateUrl>
        <ProductName>Test UPdate</ProductName>
        <PublisherName>Acharis</PublisherName>
        <SuiteName>www.acharis.com</SuiteName>
        <MinimumRequiredVersion>1.0.0.10</MinimumRequiredVersion>
        <CreateWebPageOnPublish>true</CreateWebPageOnPublish>
        <WebPage>test.html</WebPage>
        <ApplicationRevision>11</ApplicationRevision>
        <ApplicationVersion>1.0.0.%2a</ApplicationVersion>
        <UseApplicationTrust>true</UseApplicationTrust>
        <CreateDesktopShortcut>true</CreateDesktopShortcut>
        <PublishWizardCompleted>true</PublishWizardCompleted>
        <BootstrapperEnabled>true</BootstrapperEnabled>
    </PropertyGroup>

    <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
        <PlatformTarget>x86</PlatformTarget>
        <DebugSymbols>true</DebugSymbols>
        <DebugType>full</DebugType>
        <Optimize>false</Optimize>
        <OutputPath>bin\Debug\</OutputPath>
        <DefineConstants>DEBUG;TRACE</DefineConstants>
        <ErrorReport>prompt</ErrorReport>
        <WarningLevel>4</WarningLevel>
    </PropertyGroup>
    <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
        <PlatformTarget>x86</PlatformTarget>
        <DebugType>pdbonly</DebugType>
        <Optimize>true</Optimize>
        <OutputPath>bin\Release\</OutputPath>
        <DefineConstants>TRACE</DefineConstants>
        <ErrorReport>prompt</ErrorReport>
        <WarningLevel>4</WarningLevel>
    </PropertyGroup>
    <PropertyGroup>
        <ManifestCertificateThumbprint>B3D4C4433FA2AC368ACF13B0917D1CFEADFDF92A
        </ManifestCertificateThumbprint>
    </PropertyGroup>
    <PropertyGroup>
        <ManifestKeyFile>TestUpdate_TemporaryKey.pfx</ManifestKeyFile>
    </PropertyGroup>
    <PropertyGroup>
        <GenerateManifests>true</GenerateManifests>
    </PropertyGroup>
    <PropertyGroup>
        <SignManifests>true</SignManifests>
    </PropertyGroup>
    <ItemGroup>
       <Reference Include="System" />
       <Reference Include="System.Core" />
       <Reference Include="System.Xml.Linq" />
       <Reference Include="System.Data.DataSetExtensions" />
       <Reference Include="Microsoft.CSharp" />
       <Reference Include="System.Data" />
       <Reference Include="System.Deployment" />
       <Reference Include="System.Drawing" />
       <Reference Include="System.Windows.Forms" />
       <Reference Include="System.Xml" />
    </ItemGroup>
    <ItemGroup>
        <Compile Include="Form1.cs">
            <SubType>Form</SubType>
        </Compile>
        <Compile Include="Form1.Designer.cs">
            <DependentUpon>Form1.cs</DependentUpon>
        </Compile>
        <Compile Include="Program.cs" />
        <Compile Include="Properties\AssemblyInfo.cs" />
        <EmbeddedResource Include="Form1.resx">
            <DependentUpon>Form1.cs</DependentUpon>
        </EmbeddedResource>
        <EmbeddedResource Include="Properties\Resources.resx">
            <Generator>ResXFileCodeGenerator</Generator>
            <LastGenOutput>Resources.Designer.cs</LastGenOutput>
            <SubType>Designer</SubType>
        </EmbeddedResource>
        <Compile Include="Properties\Resources.Designer.cs">
            <AutoGen>True</AutoGen>
            <DependentUpon>Resources.resx</DependentUpon>
            <DesignTime>True</DesignTime>
        </Compile>
        <None Include="app.config" />
        <None Include="Properties\Settings.settings">
            <Generator>SettingsSingleFileGenerator</Generator>
            <LastGenOutput>Settings.Designer.cs</LastGenOutput>
        </None>
        <Compile Include="Properties\Settings.Designer.cs">
            <AutoGen>True</AutoGen>
            <DependentUpon>Settings.settings</DependentUpon>
            <DesignTimeSharedInput>True</DesignTimeSharedInput>
        </Compile>
        <None Include="TestUpdate_TemporaryKey.pfx" />
    </ItemGroup>
    <ItemGroup>
        <BootstrapperPackage Include="Microsoft.Net.Client.3.5">
            <Visible>False</Visible>
            <ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
            <Install>true</Install>
        </BootstrapperPackage>
        <BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
            <Visible>False</Visible>
            <ProductName>.NET Framework 3.5 SP1</ProductName>
            <Install>false</Install>
        </BootstrapperPackage>
        <BootstrapperPackage Include="Microsoft.Windows.Installer.3.1">
            <Visible>False</Visible>
            <ProductName>Windows Installer 3.1</ProductName>
            <Install>true</Install>
        </BootstrapperPackage>
    </ItemGroup>
    <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
    <!-- To modify your build process, add your task inside one of the targets below and
       Other similar extension points exist, see Microsoft.Common.targets.
    <Target Name="BeforeBuild">
    </Target>
    <Target Name="AfterBuild">
    </Target>
    -->
</Project>

我们的服务器是共享的UNIX服务器,用于更新的URL是http://www.acharis.com/Clinic/TestUpdate/test.html。 - Fayaz
请尝试从URL中删除test.html,通常URL应该以manifest(*.application文件)的目录为目标。 - igofed
这是正确的网址吗:http://www.acharis.com/Clinic/TestUpdate/Application%20Files/TestUpdate_1_0_0_5/TestUpdate.application - Fayaz
好的。csproj看起来一切正常。请清理您的C:\ Program Files%28x86%29 \ Zend \ Apache2 \ htdocs \ TestUpdate \和http://www.acharis.com/Clinic/TestUpdate/文件夹,发布应用程序并将其复制到服务器。我们需要干净的发布,没有任何文件。 - igofed
我看到有消息框,但是在您的代码中并没有呈现出来。所以,我可以看到应用程序能够正确地查看Web上的文件。看起来您的更新代码出了一些问题。请尝试在应用程序启动前设置检查更新。 - igofed
显示剩余23条评论
1个回答

4
安装/更新位置应该是一个文件夹,而不是 igofed 提到的 test.html 文件。
下面这段话并没有回答你的问题,但是希望对你有所帮助。在你的示例中调用的 ad.CheckForDetailedUpdate() 方法中存在一个 bug,它属于 .NET 框架,如果它被调用了足够多次(在长时间运行的自主应用程序中),它将开始抛出 COMExceptionInvalidOperationException 类型的异常。
现在不幸的是,我无法记起来我从哪里得知这个 bug 的,因此我无法给予应有的赞誉,但我们通过检查清单文件中的版本号并将其与当前程序集版本进行比较来解决了这个问题。
private bool CheckForUpdateAvailable()
{
    Uri updateLocation = ApplicationDeployment.CurrentDeployment.UpdateLocation;

    //Used to use the Clickonce API but we've uncovered a pretty serious bug which results in a COMException and the loss of ability
    //to check for updates. So until this is fixed, we're resorting to a very lo-fi way of checking for an update.

    WebClient webClient = new WebClient();
    webClient.Encoding = Encoding.UTF8;
    string manifestFile = webClient.DownloadString(updateLocation);

    //We have some garbage info from the file header, presumably because the file is a .application and not .xml
    //Just start from the start of the first tag
    int startOfXml = manifestFile.IndexOfAny(new[] { '<' });
    manifestFile = manifestFile.Substring(startOfXml);

    Version version;

    XmlDocument doc = new XmlDocument();

    //build the xml from the manifest
    doc.LoadXml(manifestFile);

    XmlNodeList nodesList = doc.GetElementsByTagName("assemblyIdentity");
    if (nodesList == null || nodesList.Count <= 0)
    {
        throw new XmlException("Could not read the xml manifest file, which is required to check if an update is available.");
    }

    XmlNode theNode = nodesList[0];
    version = new Version(theNode.Attributes["version"].Value);

    if (version > ApplicationDeployment.CurrentDeployment.CurrentVersion)
    {
        // update application
        return true;
    }
    return false;
}

您的更新检查调用代码...

if (ApplicationDeployment.IsNetworkDeployed)
{
    bool updateIsAvailable;

    try
    {
        updateIsAvailable = CheckForUpdateAvailable();
    }
    catch
    {
        //not network deployed etc...
    }

    if (updateIsAvailable)
    {
        ad = ApplicationDeployment.CurrentDeployment;

        if (ad == null)
        {
            return;
        }

        ad.Update();
        Application.Restart();
    }
}   

Uri updateLocation = ApplicationDeployment.CurrentDeployment.UpdateLocation; 以上代码行会抛出异常,因为在从Visual Studio运行应用程序时,该应用程序尚未安装。 - Fayaz
需要替换您对 CheckForDetailedUpdates() 的调用 - 用 if (ApplicationDeployment.IsNetworkDeployed) 包围它 - 因为正如您所说,它在调试器下无法工作。 - Patrick Allwood
谢谢,现在没有异常提示了,但它没有检查更新。刚才我重新安装了应用程序,但没有变化,它仍显示版本1.0.0.4,即使我从1.0.0.8安装它。 - Fayaz
你的安装文件夹URL和发布位置是相同还是不同?在发布页面上,点击更新按钮,尝试勾选“指定最低版本”,并输入你的最新版本号。 - Patrick Allwood
如果每个版本都被发布到像 http://www.acharis.com/Clinic/TestUpdate/Application%20Files/TestUpdate_1_0_0_5/TestUpdate.application 这样的文件夹中,那么你的安装文件夹就是 http://www.acharis.com/Clinic/TestUpdate/。您可能需要配置Web服务器的权限以允许访问此文件夹。 - Patrick Allwood
你为什么不使用ad.CheckForupdate而是使用ad.CheckForDetailedUpdate().UpdateAvailable呢?CheckForUpdate方法中是否也存在相同的.NET错误? - Kev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接