【问题标题】:How do I get an msbuild task to do config transforms on a collection of files?如何获得一个 msbuild 任务来对一组文件进行配置转换?
【发布时间】:2026-02-15 17:10:01
【问题描述】:

我正在尝试转换我拥有的项目中的所有 web.config 文件,这是我的树结构:

  • Transform.bat
  • 变换
    • ConfigTransform.proj
    • Web.Transform.config
  • 网站
    • web.config
    • 查看次数
      • web.config

还有更多的 web.config 文件,但想法是这将找到所有这些文件并对其应用相同的配置转换。

我从a blog post I found 获得了一些提示,但我陷入了最后一步,即实际的转换。中间还有一些我不太喜欢的粗糙部分(我不太明白我在做什么,而且我显然做错了)。这是我到目前为止的位置:

<Project ToolsVersion="4.0" DefaultTargets="Transform" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <UsingTask TaskName="TransformXml" AssemblyFile="Tools\Microsoft.Web.Publishing.Tasks.dll"/>

    <PropertyGroup>
        <SitePath>..\..\Website</SitePath>
        <WebConfigTransformInputFile>$(SitePath)\Web.config</WebConfigTransformInputFile>
        <WebConfigTransformFile>Web.Transform.config</WebConfigTransformFile>
        <OutDir>..\N\N\</OutDir>

    </PropertyGroup>

    <ItemGroup>
        <_FilesToTransform Include="$(SitePath)\**\web.config"/>
    </ItemGroup>

    <Target Name="Transform">

    <MakeDir Directories="@(_FilesToTransform->'$(OutDir)%(RelativeDir)')" />

    <TransformXml Source="@(_FilesToTransform->'$(OutDir)%(RelativeDir)%(Filename)%(Extension)')"
                  Transform="$(WebConfigTransformFile)"
                  Destination="@(_FilesToTransform->'$(OutDir)%(RelativeDir)%(Filename)%(Extension)')" />
    </Target>
</Project>

我的 Transform.bat 看起来像这样:

%systemroot%\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe %CD%\Transforms\ConfigTransform.proj

所以当我调用批处理时,会创建相应的目录。但是,正如您所看到的,我必须对 OutDir 有点创意,使它成为 ..\N\N。出于某种原因,如果我不这样做,OutDir 路径将与输入目录完全相同。所以我显然需要在 MakeDir 中进行一些更改,但我不确定是什么。

真正的问题出现在它开始进行转换时。我试图保持这样或这样的 TransformXml Source 参数:

@(_FilesToTransformNotAppConfig->'%(FullPath)')

后者给我一个错误“无法打开源文件:不支持给定路径的格式。”前者给了我这个输出:

Build started 30-4-2012 14:02:48.
Project "D:\Dev\transform\DoTransforms\Transforms\ConfigTransform.proj" on node 1 (default targets).
Transform:
  Creating directory "..\N\N\..\..\Website\Views\".
  Transforming Source File: ..\N\N\..\..\Website\Views\Web.config;..\N\N\..\..\Website\Web.config
D:\Dev\transform\DoTransforms\Transforms\ConfigTransform.proj(32,2): error : Could not open Source file: Could not find a part of the path 'D:\Dev\transform\DoTransforms\Website\Views\Web.config;\Website\Web.config'.
  Transformation failed
Done Building Project "D:\Dev\transform\DoTransforms\Transforms\ConfigTransform.proj" (default targets) -- FAILED.

Build FAILED.

总结一下我的问题:

  1. 如何避免 OutDir 的路径问题?我摆弄了多条路径,但我无法做到正确。
  2. 如何让 TransformXml 任务接受 Source 属性中的多个文件?

【问题讨论】:

  • 在进入你所在的位置之前,你能解释一下你想要做什么吗?
  • 转换我的解决方案中的所有配置文件。
  • 在帖子中澄清(在树结构下)。
  • 您希望将转换后的文件写入何处?
  • 我不在乎,任何与原始文件具有相同文件夹结构的地方。

标签: msbuild msbuild-task web-config-transform slowcheetah


【解决方案1】:

我认为你很接近。我在下面粘贴了一个示例,展示了如何执行此操作。

在我的示例中,我发现转换位于 web.config 文件本身旁边。对于您的方案,您可以只使用指向特定文件的 MSBuild 属性。

<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="TransformAll" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

  <UsingTask TaskName="TransformXml" AssemblyFile="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.Tasks.dll"/>

  <PropertyGroup>
    <Configuration Condition=" '$(Configuration)'=='' ">Release</Configuration>
    <OutputFolder Condition=" '$(OutputFolder)'=='' ">C:\temp\transformed-files\</OutputFolder>
  </PropertyGroup>

  <!--
  This target shows how to transform web.config with a specific transform file associated to that specific web.config file.
  -->
  <Target Name="TransformAll">

    <!-- discover the files to transform -->
    <ItemGroup>
      <FilesToTransofm Include="$(MSBuildProjectDirectory)\**\web.config"/>
    </ItemGroup>

    <!-- Ensure all target directories exist -->
    <MakeDir Directories="@(FilesToTransofm->'$(OutputFolder)%(RecursiveDir)')"/>

    <!-- TransformXml only supports single values for source/transform/destination so use %(FilesToTransofm.Identity)
         to sned only 1 value to it -->
    <TransformXml Source="%(FilesToTransofm.Identity)"
                  Transform="@(FilesToTransofm->'%(RecursiveDir)web.$(Configuration).config')"
                  Destination="@(FilesToTransofm->'$(OutputFolder)%(RecursiveDir)web.config')" />    
  </Target>

</Project>

仅供参考,您可以在 https://github.com/sayedihashimi/sayed-samples/tree/master/TransformMultipleWebConfigs 下载完整示例。

【讨论】:

  • 太棒了,稍加调整以使其按我需要的方式工作,并通过使用 MakeDir 修复错误(你忘记了反斜杠),它正是我想要的! gist.github.com/2601426
  • 还有一个问题:我可以做 $(MSBuildProjectDirectory)**\web.config 但排除找到的第一个 web.config(站点根目录中的那个)吗?
  • 仅供参考,我没有忘记斜线,它是在属性本身上定义的。在 MSBuild 中,斜线通常定义在属性的末尾,这样您在使用该属性时就不会忘记。我建议您遵循这一点,除非由于某种原因您不能这样做。关于您的其他问题,您应该添加 Exclude="$(MSBuildProjectDirectory)\web.config" 以跳过根 web.config。
  • 有道理!我见过一些不同的约定。感谢您的所有帮助,不包括它确实有效。最终结果的博客文章在这里:cultiv.nl/blog/2012/5/5/transform-umbraco-51-to-mvc-4