自动递增ClickOnce部署中的“最低要求版本”?

19
有没有一种方法可以自动递增ClickOnce部署中“最低要求版本”字段,使其始终等于当前构建编号?基本上,我希望我的部署在启动时自动更新。
我怀疑我需要一些预/后构建事件,但我希望有更简单的方法。

我有一个干净的解决方案。请在这里查看我的答案。 - orad
6个回答

24

回答可能有些晚,但我在谷歌上找到解决方案很困难,最终还是想出来了,所以想分享一下。

使用MSBuild 4版本(VS2010和VS2012),可以通过插入以下目标来实现:

  <Target Name="AutoSetMinimumRequiredVersion" BeforeTargets="GenerateDeploymentManifest">
    <FormatVersion Version="$(ApplicationVersion)" Revision="$(ApplicationRevision)">
      <Output PropertyName="MinimumRequiredVersion" TaskParameter="OutputVersion"  />
    </FormatVersion>
    <FormatVersion Version="$(ApplicationVersion)" Revision="$(ApplicationRevision)">
      <Output PropertyName="_DeploymentBuiltMinimumRequiredVersion" TaskParameter="OutputVersion"  />
    </FormatVersion>
  </Target>

$(ApplicationVersion)是可以在VS IDE项目的发布窗口手动设置的相同设置,修订部分设置为星号。$(ApplicationRevision)是用于已发布版本的实际修订版。FormatVersion任务是内置的MSBuild任务,将两者格式化为单个完整版本号。

这将把“最小需要版本”设置为与“发布版本”相同,从而确保新的部署始终被用户安装,即没有跳过更新的选项。

当然,如果您不想将最小要求版本设置为发布版本,并想使用其他源属性,则很容易修改目标,但原理是相同的。


2
我花了一段时间才弄清楚该放在哪里。你必须卸载项目,右键单击并选择“编辑Test.csproj”(或在编辑器中在VS之外打开它)。 - Dan Bechard
1
“MinimumRequiredVersion”和“_DeploymentBuiltMinimumRequiredVersion”有什么区别?如果我删除第一个FormatVersion部分,它似乎仍然可以工作。什么情况下需要它? - Dan Bechard
请注意,虽然这将正确部署MinimumRequiredVersion的值,但该值不会在您的项目文件或发布UI中表示。 - Todd Bowles
谢谢,这太棒了,应该被接受的答案。 - Theodosius Von Richthofen

7
我最终编写了一个用于同步所有版本号、然后通过单击一次即可构建和发布的 VS AddIn。这非常简单。
    Public Sub Publish()
        Try
            Dim startProjName As String = Nothing
            Dim targetProj As Project = Nothing
            Dim soln As Solution2 = TryCast(Me._applicationObject.DTE.Solution, Solution2)
            If soln IsNot Nothing Then
                For Each prop As [Property] In soln.Properties
                    If prop.Name = "StartupProject" Then
                        startProjName = prop.Value.ToString()
                        Exit For
                    End If
                Next
                If startProjName IsNot Nothing Then
                    For Each proj As Project In soln.Projects
                        If proj.Name = startProjName Then
                            targetProj = proj
                            Exit For
                        End If
                    Next
                    If targetProj IsNot Nothing Then
                        Dim currAssemVersionString As String = targetProj.Properties.Item("AssemblyVersion").Value.ToString
                        Dim currAssemVer As New Version(currAssemVersionString)
                        Dim newAssemVer As New Version(currAssemVer.Major, currAssemVer.Minor, currAssemVer.Build, currAssemVer.Revision + 1)
                        targetProj.Properties.Item("AssemblyVersion").Value = newAssemVer.ToString()
                        targetProj.Properties.Item("AssemblyFileVersion").Value = newAssemVer.ToString()
                        Dim publishProps As Properties = TryCast(targetProj.Properties.Item("Publish").Value, Properties)
                        Dim shouldPublish As Boolean = False
                        If publishProps IsNot Nothing Then
                            shouldPublish = CBool(publishProps.Item("Install").Value)
                            If shouldPublish Then
                                targetProj.Properties.Item("GenerateManifests").Value = "true"
                                publishProps.Item("ApplicationVersion").Value = newAssemVer.ToString()
                                publishProps.Item("MinimumRequiredVersion").Value = newAssemVer.ToString()
                                publishProps.Item("ApplicationRevision").Value = newAssemVer.Revision.ToString()
                            End If
                        End If
                        targetProj.Save()
                        Dim build As SolutionBuild2 = TryCast(soln.SolutionBuild, SolutionBuild2)
                        If build IsNot Nothing Then
                            build.Clean(True)
                            build.Build(True)
                            If shouldPublish Then
                                If build.LastBuildInfo = 0 Then

                                    build.Publish(True)
                                End If
                            End If
                        End If
                    End If
                End If
            End If
        Catch ex As Exception
            MsgBox(ex.ToString)
        End Try
    End Sub

@Bob 有趣的是,你的解决方案对于非 VSTO 项目可以正常工作,但对于 VSTO 项目,“Publish” 属性为 Nothing。 - Charles Chen
你能否在VSTO项目的“发布”选项卡上使用按钮进行发布? - Bob King
是的,发布按钮运行正常。你试过了吗?有可能是环境问题,但我认为它对于VSTO项目来说就是真的坏了。 - Charles Chen
在有许多开发人员参与项目的情况下,VS AddIn不是最佳选择。你是否想到了使用构建事件的方法来完成它? - Uri Abramson

5

我相信没有现成的办法来实现这个。但是自己编写也并不太难。

我的做法如下:

1)创建一个Version.Properties文件

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <Util-VersionMajor>1</Util-VersionMajor>
    <Util-VersionMinor>11</Util-VersionMinor>
    <Util-VersionBuild>25</Util-VersionBuild>
    <Util-VersionRevision>0</Util-VersionRevision>
    <Util-VersionDots>$(Util-VersionMajor).$(Util-VersionMinor).$(Util-VersionBuild).$(Util-VersionRevision)</Util-VersionDots>
    <Util-VersionUnders>$(Util-VersionMajor)_$(Util-VersionMinor)_$(Util-VersionBuild)_$(Util-VersionRevision)</Util-VersionUnders>
    <MinimumRequiredVersion>$(Util-VersionDots)</MinimumRequiredVersion>
    <ApplicationVersion>$(Util-VersionDots)</ApplicationVersion>
    <ApplicationRevision>$(Util-VersionRevision)</ApplicationRevision>
  </PropertyGroup>
</Project>

2) 将Version.Properties文件导入您的项目文件中

3) 创建一个任务,在构建时增加版本号。这是我的示例:

<Target Name="IncrementVersion" DependsOnTargets="Build" Condition="'$(BuildingInsideVisualStudio)'==''">
    <ItemGroup>
      <Util-VersionProjectFileItem Include="$(Util-VersionProjectFile)" />
    </ItemGroup>
    <PropertyGroup>
      <Util-VersionProjectFileFullPath>@(Util-VersionProjectFileItem->'%(FullPath)')</Util-VersionProjectFileFullPath>
    </PropertyGroup>
    <Exec Command="&quot;$(TfCommand)&quot; get /overwrite /force /noprompt &quot;$(Util-VersionProjectFileFullPath)&quot;" Outputs="" />
    <Exec Command="&quot;$(TfCommand)&quot; checkout /lock:checkout &quot;$(Util-VersionProjectFileFullPath)&quot;" Outputs="" />
    <Version Major="$(Util-VersionMajor)" Minor="$(Util-VersionMinor)" Build="$(Util-VersionBuild)" Revision="$(Util-VersionRevision)" RevisionType="None" BuildType="Increment">
      <Output TaskParameter="Major" PropertyName="Util-VersionMajor" />
      <Output TaskParameter="Minor" PropertyName="Util-VersionMinor" />
      <Output TaskParameter="Build" PropertyName="Util-VersionBuild" />
      <Output TaskParameter="Revision" PropertyName="Util-VersionRevision" />
    </Version>
    <XmlUpdate Prefix="msb" Namespace="http://schemas.microsoft.com/developer/msbuild/2003" XPath="/msb:Project/msb:PropertyGroup/msb:Util-VersionMajor" XmlFileName="$(Util-VersionProjectFile)" Value="$(Util-VersionMajor)" />
    <XmlUpdate Prefix="msb" Namespace="http://schemas.microsoft.com/developer/msbuild/2003" XPath="/msb:Project/msb:PropertyGroup/msb:Util-VersionMinor" XmlFileName="$(Util-VersionProjectFile)" Value="$(Util-VersionMinor)" />
    <XmlUpdate Prefix="msb" Namespace="http://schemas.microsoft.com/developer/msbuild/2003" XPath="/msb:Project/msb:PropertyGroup/msb:Util-VersionBuild" XmlFileName="$(Util-VersionProjectFile)" Value="$(Util-VersionBuild)" />
    <XmlUpdate Prefix="msb" Namespace="http://schemas.microsoft.com/developer/msbuild/2003" XPath="/msb:Project/msb:PropertyGroup/msb:Util-VersionRevision" XmlFileName="$(Util-VersionProjectFile)" Value="$(Util-VersionRevision)" />
    <Exec Command="&quot;$(TfCommand)&quot; checkin /override:AutoBuildIncrement /comment:***NO_CI***  &quot;$(Util-VersionProjectFileFullPath)&quot;" />
    <Exec Command="&quot;$(TfCommand)&quot; get /overwrite /force /noprompt &quot;$(Util-AssemblyInfoFile)&quot;" Outputs="" />
    <Exec Command="&quot;$(TfCommand)&quot; checkout /lock:checkout &quot;$(Util-AssemblyInfoFile)&quot;" Outputs="" />
    <AssemblyInfo CodeLanguage="CS" OutputFile="$(Util-AssemblyInfoFile)" AssemblyConfiguration="$(Configuration)" AssemblyVersion="$(Util-VersionMajor).$(Util-VersionMinor).$(Util-VersionBuild).$(Util-VersionRevision)" AssemblyFileVersion="$(Util-VersionMajor).$(Util-VersionMinor).$(Util-VersionBuild).$(Util-VersionRevision)" />
    <Exec Command="&quot;$(TfCommand)&quot; checkin /override:AutoBuildIncrement /comment:***NO_CI***  &quot;$(Util-AssemblyInfoFile)&quot;" />
  </Target>

这里有一些额外的 ClickOnce 技巧,点击这里查看。

0

0
这是我处理这个问题的方法。首先,我创建了一个自定义任务来包装字符串替换:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Build.Utilities;
using Microsoft.Build.Framework;

namespace SynchBuild
{
    public class RemoveAsterisk : Task
    {
        private string myVersion;

        [Required]
        public string Version
        {
            set{myVersion = value;}
        }


        [Output]
        public string ReturnValue
        {
            get { return myVersion.Replace("*", ""); }
        }


        public override bool Execute()
        {
            return true;
        }
    }
}

因此,这将被构建到 SynchBuild.dll 中,您可以在以下 UsingTask 中看到其引用。我尝试仅覆盖 MinimumRequiredVersion 属性,但似乎没有被捕获,所以我通过在我的 csproj 文件末尾添加以下行来重写 GenerateApplicationManifest 目标:

<UsingTask AssemblyFile="$(MSBuildExtensionsPath)\WegmansBuildTasks\SynchBuild.dll" TaskName="SynchBuild.RemoveAsterisk" />
  <Target Name="GenerateDeploymentManifest" DependsOnTargets="GenerateApplicationManifest" Inputs="&#xD;&#xA;            $(MSBuildAllProjects);&#xD;&#xA;            @(ApplicationManifest)&#xD;&#xA;            " Outputs="@(DeployManifest)">
    <RemoveAsterisk Version="$(ApplicationVersion)$(ApplicationRevision)">
      <Output TaskParameter="ReturnValue" PropertyName="MinimumRequiredVersion" />
    </RemoveAsterisk>
    <GenerateDeploymentManifest MinimumRequiredVersion="$(MinimumRequiredVersion)" AssemblyName="$(_DeploymentDeployManifestIdentity)" AssemblyVersion="$(_DeploymentManifestVersion)" CreateDesktopShortcut="$(CreateDesktopShortcut)" DeploymentUrl="$(_DeploymentFormattedDeploymentUrl)" Description="$(Description)" DisallowUrlActivation="$(DisallowUrlActivation)" EntryPoint="@(_DeploymentResolvedDeploymentManifestEntryPoint)" ErrorReportUrl="$(_DeploymentFormattedErrorReportUrl)" Install="$(Install)" MapFileExtensions="$(MapFileExtensions)" MaxTargetPath="$(MaxTargetPath)" OutputManifest="@(DeployManifest)" Platform="$(PlatformTarget)" Product="$(ProductName)" Publisher="$(PublisherName)" SuiteName="$(SuiteName)" SupportUrl="$(_DeploymentFormattedSupportUrl)" TargetCulture="$(TargetCulture)" TargetFrameworkVersion="$(TargetFrameworkVersion)" TrustUrlParameters="$(TrustUrlParameters)" UpdateEnabled="$(UpdateEnabled)" UpdateInterval="$(_DeploymentBuiltUpdateInterval)" UpdateMode="$(UpdateMode)" UpdateUnit="$(_DeploymentBuiltUpdateIntervalUnits)" Condition="'$(GenerateClickOnceManifests)'=='true'">
      <Output TaskParameter="OutputManifest" ItemName="FileWrites" />
</GenerateDeploymentManifest>
  </Target>

最终的结果是我们将应用程序版本和修订版本结合起来,删除星号,然后设置最低要求版本。我在发布属性中设置了自动增量应用程序版本,这就是增量发生的方式,然后我只需始终将minimumrequiredversion设置为匹配即可。我不使用团队构建,这只是为了让使用Visual Studio的开发人员可以使所有ClickOnce部署都必需。希望这有所帮助。

-1

您正在寻找应用程序更新吗?

在解决方案资源管理器中右键单击项目,然后单击发布...是获取应用程序更新的错误方法。您需要右键单击您的项目,然后单击属性,接着点击发布选项卡。点击更新...按钮,然后勾选“应用程序应该检查更新”复选框。在那里,您还可以指定应用程序的最低要求版本。(我没有使用过该功能,但更新功能是我使用ClickOnce的核心原因,它非常好用。)


1
我想要做的是自动将“应用程序所需的最低版本”递增以匹配即将发布的当前版本。 - Bob King
1
我明白了。那听起来相当有用。事实上,如果微软够聪明,他们就应该把它作为内置的复选框功能... :-) - Jared Updike
1
问题是如何自动增加该功能。 - Ed Bishop

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