How do you access publish information in a T4 Text Template?
Asked Answered
C

1

0

How do you access publish information for use in a T4 Text Template?

For example, I want to create a text template that generates an xml file that will be published with an ASP.Net Core MVC website. The generated file should be different depending on where I publish the website; Production or Test environment. So I would have something like this in the .tt file such that when it is generated it varies depending on the selected publish profile or the publish path:

<#
 if(publishing to A)
{
#>
   text output specific to A
<#
}
else if(publishing to B)
{
#>
   text output specific to B
<#
}
#>

EDIT: I just found this and it looks promising: using-msbuild-properties-in-t4-templates

Cyprus answered 5/9, 2018 at 16:6 Comment(0)
C
1

This MSDN blog by Jeremy Kuhne and this blog by Thomas Levesque and several other links such as this MSDN doc helped get it working in VS2017.

I did not have to add anything to the beginning of the .csproj file since VS2017 has the files already included by default.

In Visual Studio 2017, the Text Template Transformation component is automatically installed as part of the Visual Studio extension devlopment workload. You can also install it from the Individual components tab of Visual Studio Installer, under the Code tools category. Install the Modeling SDK component from the Individual components tab.

I ended up with the following .csproj changes at the end of the file. This will allow the selected build configuration to be availed in the T4 template and cause all templates to be regenerated on each build:

  <PropertyGroup>
    <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">15.0</VisualStudioVersion>
    <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
    <!-- Run the Transform task at the start of every build -->
    <TransformOnBuild>true</TransformOnBuild>
    <!-- -->
    <OverwriteReadOnlyOutputFiles>true</OverwriteReadOnlyOutputFiles>
    <!-- Transform every template every time -->
    <TransformOutOfDateOnly>false</TransformOutOfDateOnly>
  </PropertyGroup>

  <!-- add AFTER import for $(MSBuildToolsPath)\Microsoft.CSharp.targets -->
  <Import Project="$(VSToolsPath)\TextTemplating\Microsoft.TextTemplating.targets" />

    <ItemGroup>
    <T4ParameterValues Include="BuildConfiguration">
        <Value>$(Configuration)</Value>
        <Visible>False</Visible>
    </T4ParameterValues>
  </ItemGroup>

    <Target Name="CreateT4ItemListsForMSBuildCustomTool" BeforeTargets="CreateT4ItemLists" AfterTargets="SelectItemsForTransform">
    <ItemGroup>
        <T4Transform Include="@(CreateT4ItemListsInputs)" Condition="'%(CreateT4ItemListsInputs.Generator)' == 'MSBuild:TransformAll'" />
    </ItemGroup>
  </Target>

This is what is at the top of the csproj file but it can be configured through VS2017. The key points are the custom build configuration named Development and the defined constant of DEVELOPMENT:

<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>netcoreapp2.1</TargetFramework>
    <Configurations>Debug;Release;Development</Configurations>
  </PropertyGroup>

  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Development|AnyCPU'">
    <DebugType>none</DebugType>
    <DefineConstants>TRACE;DEVELOPMENT</DefineConstants>
  </PropertyGroup>

  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
    <DebugType>full</DebugType>
    <DefineConstants>DEBUG;TRACE</DefineConstants>
  </PropertyGroup>

  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
    <DebugType>none</DebugType>
    <DefineConstants>TRACE;RELEASE</DefineConstants>
  </PropertyGroup>

This in the T4 Template to show how to access the new BuildConfiguration parameter:

<#@ template hostspecific="true" language="C#" #>
<#@ output extension=".txt" #>
<#@ assembly name="EnvDTE" #>
<#  
    //Build time.
    string configName = Host.ResolveParameterValue("-", "-", "BuildConfiguration");
    if (string.IsNullOrWhiteSpace(configName))
    {
        try
        {
            //Design time.
            var serviceProvider = (IServiceProvider)Host;
            EnvDTE.DTE dte = (EnvDTE.DTE)serviceProvider.GetService(typeof(EnvDTE.DTE));
            configName = dte.Solution.SolutionBuild.ActiveConfiguration.Name;
        }
        catch(Exception ex)
        {
            configName = ex.Message;
        }
    }
#>
<#=configName#>

The following property settings on the .tt file:

Build Action: None
Copy to Output Directory: Do Not Copy
Custom Tool: MSBuild:TransformAll

And a custom build configuration named "Development". The code in the T4 template will pick up "Debug", "Release" and "Development". The Development build configuration is a copy of the Release configuration. The project has a Conditional Compilation Symbol of "DEVELOPMENT" so that the following code works in Program.cs to force the environment into Development mode. The Symbol can be set under Project Properties > Build > General. The publish profile is set to publish to the test server URL with the Development build configuration.

    public static void Main(string[] args)
    {
        //https://andrewlock.net/how-to-set-the-hosting-environment-in-asp-net-core/
            string mode = "";

#if DEVELOPMENT
            mode  = "DEVELOPMENT";
#elif DEBUG
            mode = "DEBUG";
#elif RELEASE
             mode = "RELEASE";
#endif

            switch (mode.ToUpper())
            {
                case "DEVELOPMENT":
                //Programmatically force the application to use the Development environment.
                    CreateWebHostBuilder(args).UseEnvironment("Development").Build().Run();
                    break;
                default:
                    CreateWebHostBuilder(args).Build().Run();
                    break;
            }
    }
Cyprus answered 23/10, 2018 at 21:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.