Текстовые преобразования T4 в VS2013 и VS2015

В нашей компании есть устаревшая система, которая в значительной степени зависит от T4, и сотрудник, который ее разработал, ушел. У нас он работал нормально, однако недавно некоторые разработчики обновились до VS2015. Преобразования T4 перестали работать для них (с ошибкой, подобной указанной ниже). Посмотрел, хотя были ссылки на Microsoft.VisualStudio.TextTemplating.12.0.dll. Они изменили ссылки на «14», и все у них заработало. Однако тот же проект, совместно используемый другими разработчиками на VS2013, больше не работал с ошибкой:

Компиляция преобразования: тип «Microsoft.VisualStudio.TextTemplating.TextTransformation» определен в сборке, на которую нет ссылок. Вы должны добавить ссылку на сборку «Microsoft.VisualStudio.TextTemplating.14.0, версия = 14.0.0.0, культура = нейтральная, PublicKeyToken = b03f5f7f11d50a3a».

Можете ли вы запустить T4 в том же проекте, который открыт как в VS2013, так и в VS2015? Одно замечание: старый сотрудник сделал зависимую сборку, из которой были получены все TextTransformations (она также предоставляет помощники, которые используются в файлах *.tt). К сожалению, он использовал интерфейс, присутствующий только в Microsoft.VisualStudio.TextTemplating.Interfaces.10.0.dll, так что старая ссылка перетаскивается. Не уверен, способствует это или нет. Но в основном вот суть:

Когда все разработчики работали на VS2013, все работало и ссылки были:

Microsoft.VisualStudio.TextTemplating.12.0.dll
Microsoft.VisualStudio.TextTemplating.Interfaces.10.0.dll
Microsoft.VisualStudio.TextTemplating.VSHost.12.0.dll

Затем, когда некоторые перешли на vs2015, единственным способом заставить его работать было заменить 12.0 * dll на 14.0, но затем разработчики vs2013 перестали работать.

ОБНОВЛЕНИЕ

Возможно, я не разъяснил нашу полную установку. У нас есть 20-30 файлов *.tt в отдельном проекте, который включен в решение с проектом, к которому будут применены преобразования текста.

  1. У нас есть вспомогательная библиотека Extensibility.CodeGeneration.dll (это также относится к файлам Microsoft.VisualStudio.TextTemplating.N.dll), в которой есть несколько статических вспомогательных функций, а также базовые классы, производные от Microsoft.VisualStudio.TextTemplating.TextTransformation.

  2. Проект 'templates', содержащий все файлы *.tt, каждый .tt файл, использует статические методы из нашей вспомогательной dll. Он также ссылается на все те же библиотеки Microsoft.VisualStudio..

  3. В каждом файле *.tt у нас есть что-то похожее на это, где AreaTemplate — это класс, определенный в самом файле *.tt и производный либо от Microsoft.VisualStudio.TextTemplating.TextTransformation, либо от одного из открытые базовые классы в нашей вспомогательной dll.

    var template = new AreaTemplate { Settings = settings, Area = area, Layouts = layouts }; Написать(шаблон.TransformText());

  4. В комментариях спросили, как я получил/использовал «хост». При поиске по коду у нас есть несколько общих сценариев (все они выполняются внутри вспомогательной dll). В каждом экземпляре хост имеет тип ITextTemplatingEngineHost.

Дело 1:

var dte = (EnvDTE.DTE)( (IServiceProvider)host ).GetService( typeof( EnvDTE.DTE ) );

Случай 2:

var hostServiceProvider = (IServiceProvider)host;

Учитывая № 3 выше, я думаю, что мне должен ссылаться на библиотеки DLL Microsoft.TextTemplating (а не только на библиотеку Interfaces) из-за использования/представления класса TextTransformation.

Кроме того, если я изменю ссылки как в моем проекте «Помощник», так и в проекте «Шаблоны» на 12.0... в vs2015, я получаю сообщение об ошибке «вы должны добавить ссылку на 12.0»... У меня есть ссылки на это в обоих применимых ( в моих глазах) проекты... не уверен, почему VS говорит мне добавить его. Я попытался добавить явную ссылку в файл *.tt, используя

<#@ assembly Name="$(ProjectDir)..\..\Assemblies\Microsoft.VisualStudio.TextTemplating.12.0.dll" #>

Но потом я получил ошибку

Тип «Microsoft.VisualStudio.TextTemplating.TextTransformation» существует как в «c:\BTR\Source\Assemblies\Microsoft.VisualStudio.TextTemplating.12.0.dll», так и в «c:\Windows\Microsoft.NET\assembly\GAC_MSIL\Microsoft». .VisualStudio.TextTemplating.14.0\v4.0_14.0.0.0__b03f5f7f11d50a3a\Microsoft.VisualStudio.TextTemplating.14.0.dll'

Это похоже на скрытую/неявную ссылку на последний Texttemplating, уже встроенный в VS??

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

Учитывая нашу настройку, дайте мне знать, если вы думаете, что я застрял или нет. Я пытался выяснить «условия» в MSBuild, чтобы помочь поддерживать обе Visual Studio, но не смог добиться успеха.

Заранее спасибо.


person Terry    schedule 06.08.2015    source источник


Ответы (3)


Попробуйте изменить ссылку с «Microsoft.VisualStudio.TextTemplating.12.0.dll» на «Microsoft.VisualStudio.TextTemplating.Interfaces.12.0.dll». Каждая новая версия служб Visual Studio будет иметь новую сборку реализации, которая реализует интерфейсы предыдущих версий. Для обеспечения обратной совместимости следует ссылаться только на сборки интерфейса, а не на сборки реализации. Возможно, вам придется изменить шаблоны, если они ссылаются на что-то, чего нет в интерфейсе.

Обновлено

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

Я думаю, что основная проблема заключается в вашем вспомогательном классе, в № 3 вы сказали, что класс AreaTemplate является производным от TextTransformation. TextTransformation находится в dll реализации, поэтому он будет существовать в каждой версии Visual Studio. Если ваша вспомогательная dll соответствует ссылке на нее с 2013 года, а затем вы используете эту dll в 2015 году, она не будет работать.

Когда шаблон T4 преобразуется, текст в файле анализируется в класс, этот класс загружается в домен приложения (отдельно от того, в котором работает Visual Studio), и вызывается метод класса TransformText. Поскольку ваши шаблоны ссылаются на ваш вспомогательный класс, вспомогательная сборка будет загружена в новый домен приложения, который, в свою очередь, также попытается загрузить туда TextTemplating 12, домен приложения не сможет разрешить ссылку 12, потому что вы используете VS 2015.

В другом направлении, когда вы ссылаетесь на текстовый шаблон 14 из 2015 года и пытаетесь использовать его в VS 2013, у вас будет та же проблема, домен приложения не сможет найти TextTemplating 14, потому что вы находитесь в VS 2013, а 14 dll не существует.

В последнем сценарии, когда вы находитесь в VS 2015 и добавляете ссылку на TextTemplating 12 в свои файлы tt, это не удается, потому что домен приложения, созданный для запуска шаблона, уже загрузил dll TextTemplating 14, тогда вы также говорите ему загрузить TextTemplating 12 длл. Это восходит к моим сообщениям в комментариях, когда я говорил об обратной совместимости VS, TextTemplating 12 и 14 имеют один и тот же класс TextTransformation в одном и том же пространстве имен, и среда выполнения не может загрузить их оба, поэтому вы получаете эту ошибку.

Несколько вещей, которые вы можете попробовать:

1) Поместите dll TextTemplating 12 в GAC на машинах VS 2015. Теоретически это позволит AppDomain T4 загружать обе копии TextTemplating, а затем VS 2015 сможет использовать версию 14, в то время как ваши файлы tt и вспомогательная dll используют версию 12. Оставьте машины VS 2013 такими же.

2) Сделайте то же самое, что и 1, но в обратном порядке, настройте проекты на 2015 год и ссылайтесь на 14 dll, а затем на машины 2013 года. сборки.

3) На машинах vs 2015 найдите способ выполнить перенаправление привязки для домена приложения T4, чтобы вызовы, обращающиеся к TextTemplating 12, разрешались в TextTemplating 14. Обычно перенаправления привязки выполняются в файлах app/web.config, но не уверен как бы вы это сделали для T4, возможно, придется заглянуть в код и посмотреть, как создается и загружается домен приложения.

person Frank    schedule 06.08.2015
comment
Ну, мне пришлось изменить его на 14.0.dll, чтобы он работал в VS2015. Я попытался добавить сборку 14 интерфейсов, но, посмотрев на ее исходный код, не похоже, что в ней есть какой-либо код? (или, по крайней мере, dotPeek это показывает). Кроме того, когда компания некоторое время назад перешла на VS2013, интерфейсы 12.0 не имели ITextTemplatingEngineHost, который мы использовали для получения свойства TemplateFile, поэтому он использовал dll интерфейсов 10.0. Итак, а) знаете ли вы, почему нет кода в 14 интерфейсах и б) какой объект заменяет ITextTemplatingEngineHost? - person Terry; 06.08.2015
comment
Я предполагаю, что в интерфейсе нет кода, потому что они не добавили ничего нового в T4 в этом выпуске, они могли внести изменения/исправления ошибок, но не расширения. Можно ссылаться на dll Interfaces.10, где живет ITextTemplatingEngineHost. Это выглядит грязно, но для обеспечения обратной совместимости VS у них есть dll интерфейсов для каждой версии. 10 для 2010 года, 11 для 12 и 14 для 15. Если они вносят изменения в T4, они помещают эти изменения в интерфейс, а затем добавляют их в dll реализации. Когда старый код вызывает движок, он получает старую версию и продолжает работать. - person Frank; 06.08.2015
comment
Поскольку похоже, что вы ничего не используете из 12 dll, попробуйте удалить ее и посмотреть, не появится ли ошибка. Кроме того, как вы получаете экземпляр хоста двигателя? есть ли такой код: IServiceProvider serviceProvider = (IServiceProvider)this.Host; - person Frank; 06.08.2015
comment
Немного обновил вопрос. - person Terry; 07.08.2015
comment
Ваш ответ был очень подробным, и я должен поверить, что он мог помочь. К сожалению (за ответ, но к счастью для меня), мне удалось заставить всех наших разработчиков перейти на vs2015, которые используют этот проект. Так что я не прошел все тесты. Спасибо за попытку. Если я попробую это на одном из старых ящиков в свободное время, я обновлю вопрос с результатом. - person Terry; 20.08.2015
comment
Путь наименьшего сопротивления будет лучшим и разумным, но если вы будете делать каждую попытку, пожалуйста, обновите этот пост, мне любопытно. - person Frank; 20.08.2015

Я столкнулся с той же проблемой, и я думаю, что у меня есть решение, которое работает - используйте свойство msbuild VisualStudioVersion для ссылки на правильную версию сборки. Что-то вроде этого:

<Reference Include="Microsoft.VisualStudio.TextTemplating.$(VisualStudioVersion)">
  <HintPath>..\Dependencies\Microsoft.VisualStudio.TextTemplating.$(VisualStudioVersion).dll</HintPath>
</Reference>
<Reference Include="Microsoft.VisualStudio.TextTemplating.Interfaces.10.0">
  <HintPath>..\Dependencies\Microsoft.VisualStudio.TextTemplating.Interfaces.10.0.dll</HintPath>
</Reference>

Убедитесь, что в папке Dependencies есть как Microsoft.VisualStudio.TextTemplating.12.0.dll, так и Microsoft.VisualStudio.TextTemplating.14.0.dll.

Кажется, работает.

person mark    schedule 11.10.2016
comment
Это выглядит очень многообещающе для людей, которые не могут ограничить всю команду одной версией VS. - person Terry; 12.10.2016

У нас сценарий очень похож на ваш, только немного сложнее, потому что наши шаблоны T4 зависят от нескольких пакетов DSL-Tools.

Я сделал несколько тестов, и на самом деле решение этой проблемы состоит в том, чтобы удалить все ссылки на Microsoft.VisualStudio.TextTemplating.12.0 и сохранить ссылки на сборки интерфейсов. Именно так, как указал Фрэнк. Это сделает проекты и шаблоны совместимыми как с Visual Studio 2013, так и с Visual Studio 2015.

К сожалению, это не помогает в нашем сценарии, потому что проекты DSL-инструментов требуют ссылок на Microsoft.VisualStudio.TextTemplating.12.0 или Microsoft.VisualStudio.TextTemplating.14.0, потому что шаблон DirectiveProcessor.tt генерирует класс, производный от RequiresProvidesDirectiveProcessor, абстрактного класса, который находится в одной из этих сборок (в зависимости от версии Visual Studio). вы хотели бы скомпилировать проект DSL-инструментов). Я предполагаю, что это одна из причин, по которой проекты DSL-инструментов обновляются, когда вы открываете их в более высоких версиях Visual Studio… Но это неприятно, потому что заставляет такие большие команды, как наша, обновлять Visual Studio одновременно.

person Hugo Quintela Ribeiro    schedule 13.01.2016