C# 项目组项目范围,或者;为什么MSBuild恨我;

C# 项目组项目范围,或者;为什么MSBuild恨我;,c#,tfs,msbuild,scope,tfsbuild,C#,Tfs,Msbuild,Scope,Tfsbuild,我有一个基于TFS的解决方案。我想更新所有适当文件的版本,我一直在努力完成这项工作。有很多关于如何做的链接,但没有一个适合我,因为有一个小问题。。。范围 <?xml version="1.0" encoding="utf-8"?> <Project DefaultTargets="DesktopBuild" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">

我有一个基于TFS的解决方案。我想更新所有适当文件的版本,我一直在努力完成这项工作。有很多关于如何做的链接,但没有一个适合我,因为有一个小问题。。。范围

<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="DesktopBuild" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
    <Target Name="DesktopBuild">
        <CallTarget Targets="GetFiles"  />

        <Message Text="CSFiles: '@(CSFiles)'" />
    </Target>

    <Target Name="GetFiles">
        <ItemGroup>
            <CSFiles Include="**\AssemblyInfo.cs" />
        </ItemGroup>
        <Message Text="CSFiles: '@(CSFiles)'" />
    </Target>
</Project>
那么,如何使我的ItemGroup具有全局范围?编译器和TeamBuild使用的所有目标文件都做同样的事情,它们的目标文件似乎都是全局的。。。我不明白为什么这对我不起作用


有什么帮助吗?

您是否尝试过使用DependsOnTarget而不是CallTarget?可能是CallTarget导致了范围问题。

我们在构建中也做了类似的事情。我们将版本作为命令行参数传递

在我们的TFSBuild.proj中,如果未提供任何版本,我们将版本设置为0.0.0.0:

<!--Our assembly version. Pass it in from the command prompt like this: /property:Version=1.0.0.0-->
<PropertyGroup>
    <Version>0.0.0.0</Version>
</PropertyGroup>

<PropertyGroup>
    <!--Used to ensure there is a newline before our text to not break the .cs files if there is no newline at the end of the file.-->
    <newLine>%0D%0A</newLine>

0.0.0.0
%0D%0A
然后我们这样做:

<Target Name="BeforeCompile">
    <!--Update our assembly version. Pass it in from the command prompt like this: /property:Version=1.0.0.0-->

    <!--attrib needs to be run first to remove the read only attribute since files from tfs are read only by default.-->
    <Exec Command='attrib -R $(SolutionRoot)\Source\Project\GlobalAssemblyInfo.cs'  />

    <WriteLinesToFile File="$(SolutionRoot)\Source\Project\GlobalAssemblyInfo.cs"
                      Lines='$(newLine)[assembly: AssemblyVersion("$(Version)")]'/>

</Target>

前面的注释是正确的,您应该将其更改为使用DependsOnTargets,而不是使用CallTarget任务。你所看到的不是范围界定问题。这个错误的主要原因是使用DependsOnTargets(这是一个更好的方法)

赛义德·易卜拉欣·哈希米


我的书:

如前所述,您应该使用DependsOnTargets。我对MSBuild范围做了一些研究,您可以在我的博客上找到我的结果:


问题是项目似乎有一个全局范围,目标似乎有一个局部范围。进入目标时,复制全局范围;退出目标时,合并回本地范围。因此,CallTarget不会获得修改后的本地作用域值,但DependsOnTargets会,因为第一个目标在进入第二个目标之前退出。

您是否正在尝试构建test.proj文件?我不确定我是否理解为什么您要指定AssemblyInfo.cs而不是仅从项目文件生成。我创建test.proj文件只是为了说明我的问题。实际上,我正试图在TFS中构建我的多个解决方案文件。这只是为了说明我在项目组和目标中看到的范围界定行为。我希望我能击败所有试图帮助的人,但显然我太“新手”。我只是想写一张便条,我非常感谢大家花了这么多时间来关注和思考这个问题。好的,这似乎给了我更多的信息。我可以使用DependsOn更改ItemGroup的作用域,但它似乎不一致。似乎使用dependson调用的目标的同级可以访问itemgroup,但父级从来没有访问过。真奇怪。是否有文件显示范围规则?我找不到它们,我想现在我必须使用复杂的依赖项而不是调用来重写我的文件。这太疯狂了,我什么都没见过。您是否尝试过将ItemGroup完全移出目标?你不想这样做有什么原因吗?或者在外部将其初始化为空(hack with Include=“*.WontExist”)我必须在目标中执行项目组,因为它在TFS构建中,我需要在获取后提取文件。。。(我正在使用beforecomile,但不管怎样)而Thomas,我试过了,不起作用。它附加到局部作用域实例的全局变量。无论您是否使用现有文件。#blessYou(以及原始问题的海报)仅供参考,Exists并没有实现代码所期望的功能。Exists检查命名文件是否存在,而不是命名变量是否存在。您可能需要条件=“$(版本)”==''。看,这个技术爱好者很聪明。:-)他说了什么。doc的标准方式是用单引号括起来,并在周围加上大量的空格。。。而且,这种方法对我来说并不可怕。我更喜欢使用MSBuild社区任务方法来更新文件。我的问题是构建要更新的文件列表,因为我有动态位置。不过谢谢。:-)谢谢克里斯。:)我们正在做一系列工作,在我们的CI环境,所以这一切都很新鲜在我的脑海里。好的技术。似乎传递的命令行值无法在PropertyGroup中被重写。@David我不知道你的意思。您可以执行您最初想要执行的操作(如果未在命令行上传递,则默认为0.0.0),例如:0.0.0将执行的操作是检查版本属性是否已传入,如果未传入,则将其设置为0.0.0.0。如果您关闭Condition属性,它将无条件地覆盖在命令行上传递的任何ws。这真的是一个bug吗?所提供的解释同样令人信服,几年后的事实也证实了这一点。这是一个bug,请参见
<Target Name="BeforeCompile">
    <!--Update our assembly version. Pass it in from the command prompt like this: /property:Version=1.0.0.0-->

    <!--attrib needs to be run first to remove the read only attribute since files from tfs are read only by default.-->
    <Exec Command='attrib -R $(SolutionRoot)\Source\Project\GlobalAssemblyInfo.cs'  />

    <WriteLinesToFile File="$(SolutionRoot)\Source\Project\GlobalAssemblyInfo.cs"
                      Lines='$(newLine)[assembly: AssemblyVersion("$(Version)")]'/>

</Target>