TextTemplating target в проекте .Net Core

Я недавно перенес тестовый проект в .NET Core 2.0. Этот тестовый проект использовал текстовые шаблоны для генерации повторяющегося кода. В предыдущем проекте была цель сборки для генерации всех T4-шаблонов перед сборкой. Поэтому сгенерированный код также не регистрируется в VCS.

Я использовал этот фрагмент в проекте, чтобы убедиться, что шаблоны построены:

<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 и там не могут быть найдены цели шаблонов текста.,

Поскольку это не помогло, я также попытался просто установить пакет Microsoft.VisualStudio.TextTemplating из Nuget, но у него есть две проблемы:

  1. он официально не поддерживает .NET Core и устанавливает для .NET 4.6.1 и
  2. Nuget, похоже, ничего не устанавливает, поэтому я не могу изменить пути в файле проекта.

Ответ 1

Вы находитесь во власти кого-то, пишущего порт для ядра dotnet.

Это старый: http://www.bricelam.net/2015/03/12/t4-on-aspnet5.html

Или используйте другой шаблонизатор полностью, хотя, конечно, я понимаю, если это не вариант.

Ответ 2

Для поддержки создания шаблонов T4 при сборке dotnet build вам необходимо использовать Custom Text Template Host, который уже существует для .NET Core (https://github.com/atifaziz/t5). Чтобы включить его, добавьте в свой проект в любой ItemGroup этот элемент: <DotNetCliToolReference Include="T5.TextTransform.Tool" Version="1.1.0-*" />. Поскольку Visual Studio уже имеет собственную реализацию Text Template Host, добавленный элемент должен быть подготовлен только для .NET Core. Например:

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

И в то же время вы должны установить в .NET Core свои настройки для хоста текстовых шаблонов Visual Studio, например: Condition="'$(MSBuildRuntimeType)'=='Full'".

Вы также должны добавить <Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk" Condition="'$(MSBuildRuntimeType)'=='Full'" /> перед импортом Microsoft.TextTemplating.targets, чтобы все работало правильно с .NET Core csproj в Visual Studio.

Если вам нужно очистить весь сгенерированный код, вы должны переименовать шаблоны из *.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 ещелучше.

Ответ 3

Или просто используйте T4Executer. Вы можете установить, какие шаблоны выполнять до сборки, после сборки или игнорировать определенные шаблоны. Хорошо работает с VS2017-19