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;
}
}