【问题标题】:Determine solution configuration (debug/release) when running a T4 template在运行 T4 模板时确定解决方案配置(调试/发布)
【发布时间】:2011-04-07 23:28:05
【问题描述】:

我有一个 T4 模板,它可以根据标志输出优化内容或标准内容。目前我正在根据需要手动更改标志。

我想做的是根据 Visual Studio 中解决方案的配置设置标志。如果设置为在调试模式下构建,我将输出标准内容。如果设置为在发布模式下构建,我会改为优化内容。我发现了另一个看起来很有希望的 T4 问题:T4 Text Template - Is it possible to get compilation symbols from host?

但是,就我而言,我想做如下的事情:

<#@ template language="C#" hostspecific="True" 
    compilerOptions="/d:$(ConfigurationName)" #>

因为我可以在汇编指令中使用 $(SolutionDir):

<#@ assembly name="$(SolutionDir)\myreference.dll" #>

我认为 /d:$(ConfigurationName) 会让我到达我需要去的地方,然后我可以执行以下操作来设置我的标志:

<#
#if Debug 
 optimize = false;
#else 
 optimize = true;
#endif 
#>

唉,这似乎不起作用。我也尝试过使用:

Host.ResolveParameterValue("-", "-", "ConfigurationName");

也无济于事。有什么想法吗?

【问题讨论】:

    标签: t4


    【解决方案1】:

    我刚一问,就在this MSDN article 的底部找到了一个sn-p,它将我带到我需要的地方。这里的答案是使用 IServiceProvider 接口获取Visual Studio DTE。这是完成它的代码(提前为硬编码的“调试”道歉):

        var serviceProvider = Host as IServiceProvider;
        var dte = serviceProvider.GetService(typeof(DTE)) as DTE;
        var configName = dte.Solution.SolutionBuild.ActiveConfiguration.Name;
        optimize = (configName != "Debug"); 
    

    更新

    此代码将检查活动项目的当前配置是否启用了优化。它仍然有一个硬编码的属性名称,但更改的可能性要小得多。此外,使用项目的优化标志对我的场景很有意义(尝试决定是否应该在自己的代码中打开优化):

        var serviceProvider = Host as IServiceProvider;
        var dte = serviceProvider.GetService(typeof(EnvDTE.DTE)) as DTE;
        config = dte.Solution
                    .FindProjectItem(Host.TemplateFile)
                    .ContainingProject
                    .ConfigurationManager
                    .ActiveConfiguration;
        foreach(Property prop in config.Properties)
        {
            if (prop.Name == "Optimize")
            {
                optimize = (bool)prop.Value;
                break;
            }
        }
    

    【讨论】:

    【解决方案2】:

    对于试图在设计时(文件保存)以及at build-time (F5/F6) 完成这项工作的人来说,两种方法是必要的。

    Emil 描述了设计时方法。对于构建时,您首先必须在项目文件中指定 T4 参数:

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

    然后你必须在你的 .tt 顶部引用它:

    <#@ parameter type="System.String" name="BuildConfiguration" #>
    

    然后查找恰好提供了其中的任何一个:

    string configurationName = Host.ResolveParameterValue("-", "-", "BuildConfiguration");
    if (string.IsNullOrWhiteSpace(configurationName))
    {
        var serviceProvider = (IServiceProvider)Host;
        var dte = (DTE)serviceProvider.GetService(typeof(DTE));
        configurationName = dte.Solution.SolutionBuild.ActiveConfiguration.Name;
    }
    

    如果您希望您的模板在这两种情况下都能正常工作,则必须包含两者的逻辑。设计时方法在构建时不起作用(DTE Host 不在附近提供解决方案),并且构建时方法在设计时不起作用(MSBuild 不在附近提供参数)。

    【讨论】:

      【解决方案3】:

      如果尝试在 VS2017 ASP.Net Core 项目中执行此操作,那么以下是对我有用的解决方案,其中突出显示了我的帖子 here

      这个MSDN blog by Jeremy Kuhne 和这个blog by Thomas Levesque 以及其他几个链接,比如这个MSDN doc 帮助它在VS2017 中工作。

      我不必在 .csproj 文件的开头添加任何内容,因为 VS2017 已默认包含这些文件。

      在 Visual Studio 2017 中,文本模板转换组件是 作为 Visual Studio 扩展的一部分自动安装 开发工作量。您也可以从个人安装它 Visual Studio 安装程序的组件选项卡,位于代码工具下 类别。从个人安装建模 SDK 组件 组件选项卡。

      我最终在文件末尾进行了以下 .csproj 更改:

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

      T4 模板中的这个:

      <#@ 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#>
      

      .tt 文件的以下属性设置:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2010-11-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-12-13
        相关资源
        最近更新 更多