在构建过程中调用文本转换

文本转换可以作为 Visual Studio 解决方案生成过程的一部分调用。 存在专用于文本转换的生成任务。 T4 生成任务运行设计时文本模板,它们还编译运行时(预处理)文本模板。

生成任务可以执行的内容存在一些差异,具体取决于您所使用的生成引擎。 在 Visual Studio 中生成解决方案时,如果设置了 hostspecific=“true” 属性,文本模板可以访问 Visual Studio API (EnvDTE)。 但是,从命令行生成解决方案或通过 Visual Studio 启动服务器生成时,情况并非如此。 在这些情况下,构建由 MSBuild 执行,并使用不同的 T4 主机。 这意味着在使用 MSBuild 生成文本模板时,不能以相同的方式访问项目文件名等内容。 但是,可以使用 生成参数将环境信息传递到文本模板和指令处理器中。

配置计算机

若要在开发计算机上启用生成任务,请安装用于 Visual Studio 的建模 SDK。

注释

文本模板转换组件作为 Visual Studio 扩展开发工作负载的一部分自动安装。 还可以从 Visual Studio 安装程序的 “单个组件 ”选项卡,在 SDK、库和框架 类别下安装它。 从“单个组件”选项卡安装建模 SDK 组件。

如果 生成服务器 在未安装 Visual Studio 的计算机上运行,请从开发计算机将以下文件复制到生成计算机:

  • %ProgramFiles(x86)%\Microsoft Visual Studio\2019\Community\MSBuild\Microsoft\VisualStudio\v16.0\TextTemplating

    • Microsoft.VisualStudio.TextTemplating.Sdk.Host.15.0.dll
    • Microsoft.TextTemplating.Build.Tasks.dll
    • Microsoft.TextTemplating.targets
  • %ProgramFiles(x86)%\Microsoft Visual Studio\2019\Community\VSSDK\VisualStudioIntegration\Common\Assemblies\v4.0

    • Microsoft.VisualStudio.TextTemplating.15.0.dll
    • Microsoft.VisualStudio.TextTemplating.Interfaces.15.0.dll
    • Microsoft.VisualStudio.TextTemplating.VSHost.15.0.dll
  • %ProgramFiles(x86)%\Microsoft Visual Studio\2019\Community\Common7\IDE\PublicAssemblies

    • Microsoft.VisualStudio.TextTemplating.Modeling.15.0.dll

小窍门

如果在构建服务器上运行 TextTemplating 构建目标时获取 MissingMethodException Microsoft.CodeAnalysis 方法,请确保 Roslyn 程序集位于与构建可执行文件(例如 msbuild.exe)相同目录中的一个名为 Roslyn 的目录中。

编辑项目文件

编辑项目文件以在 MSBuild 中配置某些功能,例如导入文本转换目标。

解决方案资源管理器中,从项目的右键单击菜单中选择 “卸载 ”。 这样,就可以在 XML 编辑器中编辑 .csproj 或 .vbproj 文件。 完成编辑后,选择“ 重新加载”。

导入文本转换目标

在 .vbproj 或 .csproj 文件中,找到最后一 Import Project 行。

在该行之后,如果该行存在,请插入文本模板化导入:

<Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v17.0\TextTemplating\Microsoft.TextTemplating.targets" />

在构建过程中转换模板

可以在项目文件中插入一些属性来控制转换任务:

  • 在每次构建开始时运行转换任务:

    <PropertyGroup>
        <TransformOnBuild>true</TransformOnBuild>
    </PropertyGroup>
    
  • 覆盖那些由于未签出而为只读的文件,例如:

    <PropertyGroup>
        <OverwriteReadOnlyOutputFiles>true</OverwriteReadOnlyOutputFiles>
    </PropertyGroup>
    
  • 每次都要对每个模板进行转换。

    <PropertyGroup>
        <TransformOutOfDateOnly>false</TransformOutOfDateOnly>
    </PropertyGroup>
    

    默认情况下,如果 T4 MSBuild 任务检测到输出文件早于以下条件,则会重新生成该文件:

    • 其模板文件
    • 包含的任何文件
    • 以前由模板或它使用的指令处理器读取的任何文件

    这是一个比 Visual Studio 中的 “转换所有模板” 命令使用的更强大的依赖项测试,它仅比较模板和输出文件的日期。

若要仅执行项目中的文本转换,请调用 TransformAll 任务:

msbuild myProject.csproj /t:TransformAll

要转换一个特定的文本模板:

msbuild myProject.csproj /t:Transform /p:TransformFile="Template1.tt"

可以在 TransformFile 中使用通配符:

msbuild dsl.csproj /t:Transform /p:TransformFile="GeneratedCode\**\*.tt"

源代码管理

没有与源代码管理系统进行特定的内置集成。 但是,您可以添加自己的扩展功能,例如签出和签入生成的文件。 默认情况下,文本转换任务可避免覆盖标记为只读的文件。 遇到此类文件时,在 Visual Studio 错误列表中记录错误,任务失败。

若要指定应覆盖只读文件,请插入此属性:

<OverwriteReadOnlyOutputFiles>true</OverwriteReadOnlyOutputFiles>

除非自定义后处理步骤,否则在覆盖文件时,警告将被记录在错误列表中。

自定义生成过程

文本转换发生在生成过程中的其他任务之前。 可以定义在转换前后调用的任务,通过设置属性 $(BeforeTransform)$(AfterTransform)

<PropertyGroup>
    <BeforeTransform>CustomPreTransform</BeforeTransform>
    <AfterTransform>CustomPostTransform</AfterTransform>
</PropertyGroup>
<Target Name="CustomPreTransform">
    <Message Text="In CustomPreTransform..." Importance="High" />
</Target>
<Target Name="CustomPostTransform">
    <Message Text="In CustomPostTransform..." Importance="High" />
</Target>

在中 AfterTransform,可以引用文件列表:

  • GeneratedFiles - 进程写入的文件列表。 如果某些文件覆盖了现有的只读文件,那么%(GeneratedFiles.ReadOnlyFileOverwritten) 为true。 这些文件可以从版本控制中签出。

  • 非生成文件列表 - 未覆盖的只读文件。

例如,定义一个任务以检出 GeneratedFiles。

OutputFilePath 和 OutputFileName

这些属性仅由 MSBuild 使用。 它们不会影响 Visual Studio 中的代码生成。 它们将生成的输出文件重定向到其他文件夹或文件。 目标文件夹必须已存在。

<ItemGroup>
  <None Include="MyTemplate.tt">
    <Generator>TextTemplatingFileGenerator</Generator>
    <OutputFilePath>MyFolder</OutputFilePath>
    <LastGenOutput>MyTemplate.cs</LastGenOutput>
  </None>
</ItemGroup>

要重定向到的有用文件夹是 $(IntermediateOutputPath)

如果指定输出文件名,则它优先于模板的输出指令中指定的扩展。

<ItemGroup>
  <None Include="MyTemplate.tt">
    <Generator>TextTemplatingFileGenerator</Generator>
    <OutputFileName>MyOutputFileName.cs</OutputFileName>
    <LastGenOutput>MyTemplate.cs</LastGenOutput>
  </None>
</ItemGroup>

如果你也在 Visual Studio 中使用Transform All或运行单个文件生成器转换模板,则不建议指定 OutputFileName 或 OutputFilePath。 最终会获得不同的文件路径,具体取决于触发转换的方式。 这可能会令人困惑。

添加引用和包含路径

主机有一组默认路径,可在其中搜索模板中引用的程序集。 若要添加到此集合,

<ItemGroup>
    <T4ReferencePath Include="$(VsIdePath)PublicAssemblies\" />
    <!-- Add more T4ReferencePath items here -->
</ItemGroup>

若要设置要搜索包含文件的文件夹,请提供分号分隔的列表。 通常,可以添加到现有文件夹列表。

<PropertyGroup>
    <IncludeFolders>
$(IncludeFolders);$(MSBuildProjectDirectory)\Include;AnotherFolder;And\Another</IncludeFolders>
</PropertyGroup>

将生成上下文数据传递到模板中

可以在项目文件中设置参数值。 例如,可以传递 生成 属性和 环境变量

<ItemGroup>
  <T4ParameterValues Include="ProjectFolder">
    <Value>$(ProjectDir)</Value>
    <Visible>false</Visible>
  </T4ParameterValues>
</ItemGroup>

在文本模板中,在模板指令中设置 hostspecific 。 使用 参数 指令获取值:

<#@template language="c#" hostspecific="true"#>
<#@ parameter type="System.String" name="ProjectFolder" #>
The project folder is: <#= ProjectFolder #>

在指令处理器中,可以调用 ITextTemplatingEngineHost.ResolveParameterValue

string value = Host.ResolveParameterValue("-", "-", "parameterName");

注释

ResolveParameterValue 仅在使用 MSBuild 时从 T4ParameterValues 中获取数据。 使用 Visual Studio 转换模板时,参数具有默认值。

在程序集和 include 指令集中使用项目属性

Visual Studio 宏(如 $(SolutionDir) 在 MSBuild 中不起作用。 可以改用项目属性。

编辑 .csproj.vbproj 文件以定义项目属性。 此示例定义名为 myLibFolder 的属性:

<!-- Define a project property, myLibFolder: -->
<PropertyGroup>
    <myLibFolder>$(MSBuildProjectDirectory)\..\libs</myLibFolder>
</PropertyGroup>

<!-- Tell the MSBuild T4 task to make the property available: -->
<ItemGroup>
    <T4ParameterValues Include="myLibFolder">
      <Value>$(myLibFolder)</Value>
    </T4ParameterValues>
  </ItemGroup>

现在,可以在程序集中使用项目属性并包括指令:

<#@ assembly name="$(myLibFolder)\MyLib.dll" #>
<#@ include file="$(myLibFolder)\MyIncludeFile.t4" #>

这些指令从 MSBuild 和 Visual Studio 主机中的 T4parameterValue 获取值。

问题解答

为何要在生成服务器中转换模板? 在签入代码之前,我已经在 Visual Studio 中转换了模板。

如果更新包含在模板中的文件或其他被读取的文件,Visual Studio 不会自动更新这些文件。 在生成过程中转换模板可确保一切最新。

转换文本模板还有哪些其他选项?

  • T4 MSbuild 模板中有很好的指南 %ProgramFiles%\Microsoft Visual Studio\2022\Enterprise\MSBuild\Microsoft\VisualStudio\v17.0\TextTemplating\Microsoft.TextTemplating.targets