在 .Net Core 项目中使用 TextTemplating

18

我最近将一个测试项目迁移到了.NET Core 2.0。那个测试项目使用文本模板来生成一些重复的代码。之前的项目有一个生成所有T4模板的构建目标,因此生成的代码也没有被检入版本控制系统。

我在项目中使用了以下代码片段来确保模板被构建:

<PropertyGroup>
  <!-- Default VisualStudioVersion to 15 (VS2017) -->
  <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">15.0</VisualStudioVersion>
  <!-- Determinate VSToolsPath -->
  <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
  <!-- Run T4 generation if there are outdated files -->
  <TransformOnBuild>True</TransformOnBuild>
  <TransformOutOfDateOnly>True</TransformOutOfDateOnly>
</PropertyGroup>
<!-- Import TextTemplating target -->
<Import Project="$(VSToolsPath)\TextTemplating\Microsoft.TextTemplating.targets" />

我的第一种方法是保留这个片段,并将其复制到新的 .NET Core 项目文件中。

在 Visual Studio 中,这种方法可以工作,因为显然会正确设置 VSToolsPath。 但是,当我运行 .NET Core SDK 工具时,例如使用 dotnet test(就像我在构建服务器上做的那样),VSToolsPath 将映射到 Program Files\dotnet\sdk\2.0.3,在那里,找不到文本模板目标。

由于那种方法不起作用,我还尝试了简单地从 Nuget 安装 Microsoft.VisualStudio.TextTemplating 包,但是有两个问题:

  1. 它并没有正式支持 .NET Core,并且安装的是 .NET 4.6.1
  2. Nuget 似乎没有安装任何东西,所以我无法在项目文件中调整路径。

1
你找到解决方案了吗? - Soenhay
5个回答

5
为了在dotnet build时支持构建T4模板,您需要使用自定义文本模板主机,它已经存在于.NET Core中(https://github.com/atifaziz/t5)。为了包含它,请在任何ItemGroup中添加以下元素: <DotNetCliToolReference Include="T5.TextTransform.Tool" Version="1.1.0-*" />。 由于Visual Studio已经有了自己的文本模板主机实现,您添加的元素应该只针对.NET Core进行条件判断。例如:
<ItemGroup Condition="'$(MSBuildRuntimeType)'=='Core'">
    <DotNetCliToolReference Include="T5.TextTransform.Tool" Version="1.1.0-*" />
</ItemGroup>

同时,您应该将 Visual Studio 的文本模板主机的设置从 .NET Core 中条件化掉,像这样:Condition="'$(MSBuildRuntimeType)'=='Full'"
在导入 Microsoft.TextTemplating.targets 之前,您还应该添加 <Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk" Condition="'$(MSBuildRuntimeType)'=='Full'" />,使一切在 Visual Studio 中使用 .NET Core csproj 正常运行。
如果您需要能够清理所有生成的代码,您应该将模板从 *.tt 重命名为 *.Generated.tt,所有代码将在 *.Generated.cs 下生成,并且可以在 dotnet clean 操作中过滤这些文件。
以下是在您的 csproj 中完整示例:
<!-- T4 build support for .NET Core (Begin) -->

<ItemGroup Condition="'$(MSBuildRuntimeType)'=='Core'">
  <DotNetCliToolReference Include="T5.TextTransform.Tool" Version="1.1.0-*" />
  <TextTemplate Include="**\*.Generated.tt" />
  <Generated Include="**\*.Generated.cs" />
</ItemGroup>

<Target Name="TextTemplateTransform" BeforeTargets="BeforeBuild" Condition="'$(MSBuildRuntimeType)'=='Core'">
  <ItemGroup>
    <Compile Remove="**\*.cs" />
  </ItemGroup>
  <Exec WorkingDirectory="$(ProjectDir)" Command="dotnet tt %(TextTemplate.Identity)" />
  <ItemGroup>
    <Compile Include="**\*.cs" />
  </ItemGroup>
</Target>

<Target Name="TextTemplateClean" AfterTargets="Clean">
  <Delete Files="@(Generated)" />
</Target>

<!-- T4 build support for .NET Core (End) -->


<!-- T4 build support for Visual Studio (Begin) -->

<PropertyGroup Condition="'$(MSBuildRuntimeType)'=='Full'">
  <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
  <!-- This is what will cause the templates to be transformed when the project is built (default is false) -->
  <TransformOnBuild>true</TransformOnBuild>
  <!-- Set to true to force overwriting of read-only output files, e.g. if they're not checked out (default is false) -->
  <OverwriteReadOnlyOutputFiles>true</OverwriteReadOnlyOutputFiles>
  <!-- Set to false to transform files even if the output appears to be up-to-date (default is true)  -->
  <TransformOutOfDateOnly>false</TransformOutOfDateOnly>
</PropertyGroup>

<Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk" Condition="'$(MSBuildRuntimeType)'=='Full'" />
<Import Project="$(VSToolsPath)\TextTemplating\Microsoft.TextTemplating.targets" Condition="'$(MSBuildRuntimeType)'=='Full'" />

<!-- T4 build support for Visual Studio (End) -->

如果您不想重命名模板文件并且不需要清理它们,那么请将以下内容替换为:
  <TextTemplate Include="**\*.Generated.tt" />
  <Generated Include="**\*.Generated.cs" />

使用:

  <TextTemplate Include="**\*.tt" />

并删除:

<Target Name="TextTemplateClean" AfterTargets="Clean">
  <Delete Files="@(Generated)" />
</Target>

更多信息请参见:

如何在dotnet build上设置代码生成: https://notquitepure.info/2018/12/12/T4-Templates-at-Build-Time-With-Dotnet-Core/

如何为Visual Studio和.NET Core csproj构建设置代码生成: https://thomaslevesque.com/2017/11/13/transform-t4-templates-as-part-of-the-build-and-pass-variables-from-the-project/

从单个T4模板生成多个文件的完整示例: https://github.com/Konard/T4GenericsExample

更新:

GitHub.com/Mono/T4 更好


1

或者只需使用T4Executer。您可以设置在构建之前、构建之后执行哪些模板,或忽略特定的模板。与VS2017-19配合良好。


1

1

Konard的评论“更新:https://github.com/mono/t4更好了”进行拓展。

将Mono/T4(dotnet-t4)安装为工具

  • 如果您正在运行Azure DevOps管道,可以将其添加为步骤 - 参见https://dev59.com/f7noa4cB1Zd3GeqPWb0e#60667867的第一部分。

  • 如果您在Linux Dockerfile中构建,请在构建之前添加以下内容(我们在alpine上使用了.NET 6,但在其他发行版和版本上也应该可以):

# you will see a warning if this folder is not on PATH
ENV PATH="${PATH}:/root/.dotnet/tools"
RUN dotnet tool install -g dotnet-t4

如果你想在你的开发机上使用这个工具,而不是使用VS TextTemplating,可以从powershell运行一次性安装(但你团队中的每个开发者都需要这样做):
dotnet tool install -g dotnet-t4

在开发机器和流水线上运行t4

dotnet-t4的设置与 Konard's answer中的t5非常相似。

选项1 - 在您的开发机器上安装dotnet-t4

将以下内容添加到您的csproj文件中。不需要条件设置。

  <!-- T4 build support for .NET Core (Begin) -->

  <ItemGroup>
    <TextTemplate Include="**\*.tt" />
  </ItemGroup>

  <Target Name="TextTemplateTransform" BeforeTargets="BeforeBuild">
    <ItemGroup>
      <Compile Remove="**\*.cs" />
    </ItemGroup>
    <Exec WorkingDirectory="$(ProjectDir)" Command="t4 %(TextTemplate.Identity)" />
    <ItemGroup>
      <Compile Include="**\*.cs" />
    </ItemGroup>
  </Target>

  <!-- T4 build support for .NET Core (End) -->

选项2-在您的开发机器上使用VS模板
如果您不想让每个人都在本地安装该工具,您仍然可以按照Konard的答案向项目添加条件构建步骤。请注意,Visual Studio现在是64位的,因此您可以使用MSBuildExtensionsPath而不是MSBuildExtensionsPath32:
  <!-- T4 build support for .NET Core (Begin) -->

  <ItemGroup Condition="'$(MSBuildRuntimeType)'=='Core'">
    <TextTemplate Include="**\*.tt" />
  </ItemGroup>

  <Target Name="TextTemplateTransform" BeforeTargets="BeforeBuild" Condition="'$(MSBuildRuntimeType)'=='Core'">
    <ItemGroup>
      <Compile Remove="**\*.cs" />
    </ItemGroup>
    <Exec WorkingDirectory="$(ProjectDir)" Command="t4 %(TextTemplate.Identity)" />
    <ItemGroup>
      <Compile Include="**\*.cs" />
    </ItemGroup>
  </Target>

  <!-- T4 build support for .NET Core (End) -->

  <!-- T4 build support for Visual Studio (Begin) -->

  <PropertyGroup Condition="'$(MSBuildRuntimeType)'=='Full'">
    <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
    <TransformOnBuild>true</TransformOnBuild>
    <!--Other properties can be inserted here--> 
    <!--Set to true to force overwriting of read-only output files, e.g. if they're not checked out (default is false)--> 
    <OverwriteReadOnlyOutputFiles>true</OverwriteReadOnlyOutputFiles>
    <!--Set to false to transform files even if the output appears to be up-to-date (default is true)-->  
    <TransformOutOfDateOnly>false</TransformOutOfDateOnly>
  </PropertyGroup>

  <Import Project="$(VSToolsPath)\TextTemplating\Microsoft.TextTemplating.targets" Condition="'$(MSBuildRuntimeType)'=='Full'" />

  <!-- T4 build support for Visual Studio (End) -->

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接