Определите конфигурацию решения (отладка / выпуск) при запуске шаблона T4

У меня есть шаблон T4, который может выводить либо оптимизированный, либо стандартный контент на основе флага. В настоящее время я вручную меняю флаг, исходя из своих потребностей.

Что бы я хотел сделать, так это установить флаг на основе конфигурации решения в Visual Studio. Если установить сборку в режиме отладки, я бы выводил стандартный контент. Если настроен на сборку в режиме выпуска, я бы вместо этого оптимизировал контент. Я нашел еще один многообещающий вопрос T4: Текстовый шаблон T4 - Можно ли получить символы компиляции с хоста?

Однако в моем случае я бы хотел сделать что-то вроде следующего:

<#@ 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
person Emil Lerch    schedule 07.04.2011    source источник


Ответы (3)


Как только я спрашиваю, я нахожу отрывок внизу этой статьи MSDN это приведет меня туда, где мне нужно быть. Ответ здесь - использовать интерфейс 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;
        }
    }
person Emil Lerch    schedule 07.04.2011
comment
Есть ли в документации MSDN страница для класса DTE? Я искал это и не мог найти. - person rstackhouse; 10.07.2013
comment
Неважно. Думаю, я только что нашел его: msdn. microsoft.com/en-us/library/vstudio/EnvDTE(v=vs.100).aspx - person rstackhouse; 10.07.2013
comment
SDTE? Это опечатка? - person Ronnie Overby; 24.09.2013
comment
@RonnieOverby Нет - это имя интерфейса: msdn .microsoft.com / en-us / library / - person Emil Lerch; 26.09.2013
comment
Как я могу получить раздел ProjectConfigurationPlatforms для каждого проекта? - person Kiquenet; 04.12.2013

Для людей, пытающихся выполнить эту работу во время разработки (сохранение файла), а также во время сборки (F5 / F6) необходимы два метода.

Эмиль описывает метод разработки. Для времени сборки вы сначала должны указать параметр 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 не может предоставить Решение), а метод времени сборки не работает во время разработки (MSBuild не может предоставить параметр).

person Calvin Fisher    schedule 26.11.2014

Если вы пытаетесь сделать это в проекте VS2017 ASP.Net Core, то ниже приводится решение, которое сработало для меня с основными моментами из моего сообщения здесь .

Этот блог MSDN Джереми Kuhne и это блог Томаса Левеска и несколько других ссылок, таких как эта Документ MSDN помог заставить его работать в VS2017.

Мне не нужно было ничего добавлять в начало файла .csproj, поскольку VS2017 имеет файлы, уже включенные по умолчанию.

В Visual Studio 2017 компонент преобразования текстового шаблона автоматически устанавливается как часть рабочей нагрузки разработки расширения Visual Studio. Вы также можете установить его на вкладке «Отдельные компоненты» установщика Visual Studio в категории «Инструменты для кода». Установите компонент Modeling 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
person Soenhay    schedule 24.10.2018