如何始终在MSBuild中执行目标

如何始终在MSBuild中执行目标,msbuild,Msbuild,我有一个MSBuild文件,它在编译应用程序之前操作AssemblyInfo文件。在生成结束时,它将恢复AssemblyInfo文件。它通过备份文件、操作文件,然后在构建时恢复文件来实现这一点 除非在构建过程中发生错误,否则这种方法工作得相当好。然后它不会还原原始文件。有没有一种方法可以让MSBuild在生成结束时执行目标,无论它成功还是失败?我从未使用过它,但从文档中可以看出,它对您尝试实现的目标很有用 使一个或多个目标执行, 如果ContinueOnError属性为 对于失败的任务,为fal

我有一个MSBuild文件,它在编译应用程序之前操作AssemblyInfo文件。在生成结束时,它将恢复AssemblyInfo文件。它通过备份文件、操作文件,然后在构建时恢复文件来实现这一点


除非在构建过程中发生错误,否则这种方法工作得相当好。然后它不会还原原始文件。有没有一种方法可以让MSBuild在生成结束时执行目标,无论它成功还是失败?

我从未使用过它,但从文档中可以看出,它对您尝试实现的目标很有用

使一个或多个目标执行, 如果ContinueOnError属性为 对于失败的任务,为false


根据你对最初问题的最后评论,我将采取另一种方法,忘记你目前正在采取的方法。您应该知道,您的版本信息不必位于AssemblyInfo.cs文件中。它可以在任何代码文件中,只要您只定义了AssemblyVersion和AssemblyFileVersion属性一次。话虽如此,我要做的是遵循以下步骤:

  • 从AssemblyInfo.cs中删除AssemblyVersion和AssemblyFileVersion
  • 创建一个新文件,根据需要命名。在我的示例中,我将其放在Properties\VersionInfo.cs不要将此文件添加到项目。
  • 编辑项目文件,以便仅在需要时将该文件包括在要编译的文件列表中
  • 让我们在#3上展开一点。生成.NET项目时,项目本身是一个MSBuild文件。在该文件中,您将发现一个声明为Compile的项。这是将发送到要编译的编译器的文件列表。您可以从该列表中动态包含/排除文件。在这种情况下,仅当在生成服务器上生成时(或定义的任何其他条件),才希望包含VersionInfo.cs文件。对于本例,我将该条件定义为项目是否以发布模式构建。因此,对于发布模式,VersionInfo.cs将被发送到编译器,而对于其他版本则不会。以下是VersionInfo.cs的内容

    VersionInfo.cs

    [assembly: System.Reflection.AssemblyVersion("1.2.3.4")]
    [assembly: System.Reflection.AssemblyFileVersion("1.2.3.4")]
    
    为了将其挂接到构建过程中,您必须编辑项目文件。在该文件中,您将找到一个元素(根据项目类型,可能不止一个)。您应该在此处添加类似于以下内容的目标

    <Target Name="BeforeCompile">
      <ItemGroup Condition=" '$(Configuration)'=='Release' ">
        <Compile Include="Properties\VersionInfo.cs" />
      </ItemGroup>
    </Target>
    
    
    
    这里我所做的是在编译之前定义一个目标,这是一个众所周知的目标,您可以覆盖它。有关其他类似目标,请参见此。基本上,这是一个在调用编译器之前总是被调用的目标。在这个目标中,仅当Configuration属性设置为release时,我才将VersionInfo.cs添加到编译项中。您可以将该属性定义为您想要的任何内容。例如,如果您将TFS作为构建服务器,那么它可能是

    <Target Name="BeforeCompile">
      <ItemGroup Condition=" '$(TeamFoundationServerUrl)'!='' ">
        <Compile Include="Properties\VersionInfo.cs" />
      </ItemGroup>
    </Target>
    
    
    
    因为我们知道TeamFoundationServerUrl仅在通过TFS构建时定义

    如果您是从命令行构建表单,则类似于

    <Target Name="BeforeCompile">
      <ItemGroup Condition=" '$(IncludeVersionInfo)'=='true' ">
        <Compile Include="Properties\VersionInfo.cs" />
      </ItemGroup>
    </Target>
    
    
    

    构建项目时,只需执行msbuild.exe YourProject.proj/p:IncludeVersion=true。注意:构建解决方案时,这将不起作用。

    如何更改问题:

    • 将“模板”AssemblyInfo.cs.template添加到版本控制中,该版本控制表示“理想”AssemblyInfo.cs,其中包含正则表达式挂钩
    • 在构建之前,将模板复制到real并应用正则表达式
    • 为AssemblyInfo.cs添加某种类型的subversion ignore(我不是svn专家,但我非常确定有一种方法可以让它忽略某些文件)
    • 如果开发人员需要添加通常出现在AssemblyInfo.cs(例如InternalsVisibleTo)中的某种自定义项,则让他们将其添加到另一个签入的.cs文件中

    作为进一步的改进,将Sayed的解决方案与我的解决方案结合起来,从实际的AssemblyInfo.cs中删除版本信息内容,并拥有一个已签入的VersionInfo.cs.template,该模板在BeforeBuild中创建一个VersionInfo.cs

    我已经在为我的自定义目标/任务使用OnError元素。这是非常有效的。问题是当错误发生在我控制的目标之外时。因此,我想要一个超级“全包”,它可以作为任何任务的OnError。@Jason,在这种情况下,我很抱歉不能提供任何进一步的帮助。MSBuild中没有内置这样的功能。你能更好地解释一下你在做什么,以便其他人能提供一些选择吗?当然。。。基本上我要做的是:1)将assemblyinfo.cs复制到备份文件(assemblyinfo.cs.original)2)编辑assemblyinfo.cs以包含有关版本控制的信息。版本控制信息来自自定义MSBuild任务。3.)生成应用程序和/或程序集4.)用原始文件(assemblyInfo.cs.original)替换assemblyInfo.cs。如果生成过程中出现任何错误,我希望执行步骤4。很有趣,但我不确定这是如何解决问题的。让我详细介绍一下我正在做的事情。当我希望发送一个版本进行测试时,我会在subversion中创建一个分支,指定版本号。然后,我的自定义MSBuild任务将读取工作副本所在的分支(以及修订号等其他信息)。然后修改assemblyinfo.cs以嵌入此类信息。失败时,它将恢复文件的原始版本。这样做的原因是为了让我的正则表达式“知道”在哪里修改信息。更重要的是,我不会以这种方式创建无休止的未提交更改循环。如果我提交版本1.0.0.0,我不会因为只是构建项目而更改文件。相反,只有在需要时(在构建过程中)才会更改文件。我不希望我的开发人员必须记住手动更改这些信息。这个