在构建后事件期间确定程序集版本

Win*_*ith 53 .net c# deployment visual-studio-2005 visual-studio

假设我想创建一个随每个版本一起提供的静态文本文件.我希望使用版本的版本号(如中所述AssemblyInfo.cs)更新文件,但我不想手动执行此操作.

我希望我可以使用post-build事件并将版本号提供给批处理文件,如下所示:

call foo.bat $(AssemblyVersion)
Run Code Online (Sandbox Code Playgroud)

但是我找不到任何合适的变量或宏来使用.

有没有办法实现这一点,我错过了?

Bre*_*ias 90

如果(1)您不想下载或创建检索程序集版本的自定义可执行文件,并且(2)您不介意编辑Visual Studio项目文件,那么有一个简单的解决方案允许您使用宏看起来像这样:

@(目标 - > '%(版)')

@(VersionNumber)
Run Code Online (Sandbox Code Playgroud)

要完成此任务,请卸载您的项目.如果某个项目定义了一个<PostBuildEvent>属性,请将其从项目中删除并暂时保存在其他位置(记事本?).然后在项目的最后,就在结束标记之前,放置:

<Target Name="PostBuildMacros">
  <GetAssemblyIdentity AssemblyFiles="$(TargetPath)">
    <Output TaskParameter="Assemblies" ItemName="Targets" />
  </GetAssemblyIdentity>
  <ItemGroup>
    <VersionNumber Include="@(Targets->'%(Version)')"/>
  </ItemGroup>
</Target>
<PropertyGroup>
  <PostBuildEventDependsOn>
    $(PostBuildEventDependsOn);
    PostBuildMacros;
  </PostBuildEventDependsOn>    
  <PostBuildEvent>echo HELLO, THE ASSEMBLY VERSION IS: @(VersionNumber)</PostBuildEvent>
</PropertyGroup>
Run Code Online (Sandbox Code Playgroud)

此代码段中已包含一个示例<PostBuildEvent>.不用担心,您可以在重新加载项目后将其重置为真正的构建后事件.

现在按照承诺,使用此宏可以为您的post build事件提供程序集版本:

@(VersionNumber)
Run Code Online (Sandbox Code Playgroud)

完成!

  • 这应该是可以接受的答案,因为它不会破坏外部(自动)构建系统(如Azure DevOps)的构建。事实上; 任何人都可以构建它,而无需先安装一些工具。 (2认同)

小智 16

如果您更喜欢编写脚本,这些方法可能对您有用:

如果您使用的是构建后事件,则可以使用filever.exe工具从已构建的程序集中获取它:

for /F "tokens=4" %%F in ('filever.exe /B /A /D bin\debug\myapp.exe') do (
  set VERSION=%%F
)
echo The version is %VERSION%
Run Code Online (Sandbox Code Playgroud)

从这里获取filever.exe:http://support.microsoft.com/kb/913111

如果您正在使用预构建事件,则可以将其从AssemblyInfo.cs文件中取出,如下所示:

set ASMINFO=Properties\AssemblyInfo.cs
FINDSTR /C:"[assembly: AssemblyVersion(" %ASMINFO% | sed.exe "s/\[assembly: AssemblyVersion(\"/SET CURRENT_VERSION=/g;s/\")\]//g;s/\.\*//g" >SetCurrVer.cmd
CALL SetCurrVer.cmd
DEL SetCurrVer.cmd
echo Current version is %CURRENT_VERSION%
Run Code Online (Sandbox Code Playgroud)

这使用unix命令行工具sed,您可以从许多地方下载,例如:http://unxutils.sourceforge.net/ - iirc,一个正常工作.


Win*_*ith 12

作为一种解决方法,我编写了一个托管控制台应用程序,它将目标作为参数,并返回版本号.

我仍然有兴趣听一个更简单的解决方案 - 但我发布这个以防其他人发现它有用.

using System;
using System.IO;
using System.Diagnostics;
using System.Reflection;

namespace Version
{
    class GetVersion
    {
        static void Main(string[] args)
        {
            if (args.Length == 0 || args.Length > 1) { ShowUsage(); return; }

            string target = args[0];

            string path = Path.IsPathRooted(target) 
                                ? target 
                                : Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName) + Path.DirectorySeparatorChar + target;

            Console.Write( Assembly.LoadFile(path).GetName().Version.ToString(2) );
        }

        static void ShowUsage()
        {
            Console.WriteLine("Usage: version.exe <target>");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


Eri*_*dil 8

这个答案是布伦特阿里亚斯答案的一个小修改.他的PostBuildMacro对我来说效果很好,直到Nuget.exe的版本更新.

在最近的版本中,Nuget修剪了包版本号的非重要部分,以获得类似"1.2.3"的语义版本.例如,程序集版本"1.2.3.0"由Nuget.exe"1.2.3"格式化.并且"1.2.3.1"按预期格式化为"1.2.3.1".

由于我需要推断Nuget.exe生成的确切包文件名,我现在使用这个自适应宏(在VS2015中测试):

<Target Name="PostBuildMacros">
  <GetAssemblyIdentity AssemblyFiles="$(TargetPath)">
    <Output TaskParameter="Assemblies" ItemName="Targets" />
  </GetAssemblyIdentity>
  <ItemGroup>
    <VersionNumber Include="$([System.Text.RegularExpressions.Regex]::Replace(&quot;%(Targets.Version)&quot;, &quot;^(.+?)(\.0+)$&quot;, &quot;$1&quot;))" />
  </ItemGroup>
</Target>
<PropertyGroup>
  <PostBuildEventDependsOn>
    $(PostBuildEventDependsOn);
    PostBuildMacros;
  </PostBuildEventDependsOn>    
  <PostBuildEvent>echo HELLO, THE ASSEMBLY VERSION IS: @(VersionNumber)</PostBuildEvent>
</PropertyGroup>
Run Code Online (Sandbox Code Playgroud)

更新2017-05-24:我以这种方式纠正了正则表达式:"1.2.0.0"将被翻译为"1.2.0"而不是之前编码的"1.2".


要回答Ehryk Apr的评论,您可以调整正则表达式以仅保留版本号的某些部分.作为保留"Major.Minor"的示例,替换:

<VersionNumber Include="$([System.Text.RegularExpressions.Regex]::Replace(&quot;%(Targets.Version)&quot;, &quot;^(.+?)(\.0+)$&quot;, &quot;$1&quot;))" />
Run Code Online (Sandbox Code Playgroud)

通过

<VersionNumber Include="$([System.Text.RegularExpressions.Regex]::Replace(&quot;%(Targets.Version)&quot;, &quot;^([^\.]+)\.([^\.]+)(.*)$&quot;, &quot;$1.$2&quot;))" />
Run Code Online (Sandbox Code Playgroud)


Kir*_*san 6

我不知道为什么,但 Brent Arias 宏对我不起作用(@(VersionNumber)总是空的):( .Net6 VS2022。我最终得到了稍微修改过的版本:

<Target Name="GetVersion" AfterTargets="PostBuildEvent">
    <GetAssemblyIdentity AssemblyFiles="$(TargetPath)">
        <Output TaskParameter="Assemblies" ItemName="AssemblyInfo" />
    </GetAssemblyIdentity>
    <PropertyGroup>
        <VersionInfo>%(AssemblyInfo.Version)</VersionInfo>
    </PropertyGroup>
    <!--And use it after like any other variable:-->
    <Message Text="VersionInfo = $(VersionInfo)" Importance="high" />
</Target>
Run Code Online (Sandbox Code Playgroud)