У меня много проблем, пытаясь определить, почему MSBuild блокирует доступ к dll, используемому внутри нового шаблона T4, который я только что создал.
Проблема довольно трудно объяснить (и даже спросить, как видно из названия).
Я создал шаблон T4 для создания класса С#, который является оберткой для N других классов, которые у нас есть. Это было решение, с которым я придумал выставить несколько служб WCF по той же конечной точке.
Сам код шаблона использует сборку (Mobiltec.Framework.dll), которая содержит различные методы расширения для упрощения кода шаблона. Сначала я просто добавил файл .tt в проект и пошел с ним: он обновил сгенерированный файл всякий раз, когда изменился .tt, как и ожидалось.
Так как этот шаблон читает другие сборки и генерирует класс на их основе, я хотел бы убедиться, что он преобразовал вывод в каждую сборку, чтобы не забыть разработчикам обновлять выходные данные и т.д.
После нескольких дней поиска я наконец пришел к довольно приличному решению, и шаблоны трансформировались на каждой сборке почти "отлично". Проблема заключается в том, что всякий раз, когда я создаю проект, и шаблон преобразуется, он блокирует доступ к вышеупомянутой dll, не позволяя мне впоследствии удалять или обновлять файл. Мне нужно закрыть Visual Studio, чтобы он выпустил файл.
Теперь это не большая проблема на локальных машинах-разработчиках, но он не работает на сервере сборки, потому что вывод там находится в одной папке:
- Процесс сборки начинает компиляцию нашего главного решения.
- Проект, содержащий шаблон T4, скомпилирован, и класс сгенерирован
- Другой проект скомпилирован и пытается изменить DLL в выходной папке, не выполнив сборку после попытки 10 раз
Является ли это ошибкой в системе текстовых шаблонов или я могу ошибиться, что вызывает блокировку файла?
Обновление
Я попытаюсь объяснить немного лучше, как все настроено здесь, так что, возможно, вы, ребята, можете лучше понять проблему.
Существует файл шаблона .tt, по одному для каждого нашего веб-приложения (всего 4). Этот шаблон отвечает за автоматическое создание класса-оболочки для всех наших контрактов услуг WCF. Сами контракты разделяются в другой сборке (также по одному для каждого из четырех компонентов), чтобы они могли делиться с клиентами, не перенося все другие зависимости.
Мне пришлось реализовать кучу методов для печати, используя отражение, подписи, элементы и типы из каждой сборки, чтобы генерировать текст, который мог бы скомпилироваться как действительный класс. Я реализовал эти методы на общей сборке.
Каждый файл tt ссылается на эту общую сборку вместе с сборкой контрактов на обслуживание для создания этого класса-оболочки. В шаблоне есть несколько строк, например:
<#@ assembly name="Mobiltec.M3.EG.Services.dll" #>
<#@ assembly name="Mobiltec.M3.Common.dll" #>
Поскольку нам нужны эти шаблоны для преобразования в каждой сборке, я изменил файлы проекта, чтобы включить это, и установил SDK Visual Studio и визуализацию и моделирование SDK, следуя этот совет.
Теперь, всякий раз, когда я делаю какие-либо изменения в коде в любой из сборников или их зависимостей, я получаю такие сообщения:
Error 1516 Compiling transformation: Metadata file 'Mobiltec.M3.EG.Services.dll' could not be found. Line=0, Column=0 Mobiltec.M3.EG
Error 1517 Compiling transformation: Metadata file 'Mobiltec.M3.Common.dll' could not be found. Line=0, Column=0 Mobiltec.M3.EG
Или:
Error 395 Could not copy "D:\TFS05\M3\Desenvolvimento\Feature-ODataM3S\ProjetosManutencao\Mobiltec.M3.Common\Mobiltec.M3.Common.Desktop\bin\Mobiltec.M3.Common.dll" to "bin\Mobiltec.M3.Common.dll". Exceeded retry count of 10. Failed. Mobiltec.M3.EG
Error 396 Unable to copy file "D:\TFS05\M3\Desenvolvimento\Feature-ODataM3S\ProjetosManutencao\Mobiltec.M3.Common\Mobiltec.M3.Common.Desktop\bin\Mobiltec.M3.Common.dll" to "bin\Mobiltec.M3.Common.dll". The process cannot access the file 'bin\Mobiltec.M3.Common.dll' because it is being used by another process. Mobiltec.M3.EG
Error 407 Could not copy "D:\TFS05\M3\Desenvolvimento\Feature-ODataM3S\ProjetosManutencao\Mobiltec.M3.EG\Mobiltec.M3.EG.Services\bin\Debug\Mobiltec.M3.EG.Services.dll" to "bin\Mobiltec.M3.EG.Services.dll". Exceeded retry count of 10. Failed. Mobiltec.M3.EG
Error 408 Unable to copy file "D:\TFS05\M3\Desenvolvimento\Feature-ODataM3S\ProjetosManutencao\Mobiltec.M3.EG\Mobiltec.M3.EG.Services\bin\Debug\Mobiltec.M3.EG.Services.dll" to "bin\Mobiltec.M3.EG.Services.dll". The process cannot access the file 'bin\Mobiltec.M3.EG.Services.dll' because it is being used by another process. Mobiltec.M3.EG
Кроме того, когда я пытаюсь удалить папки bin/obj, хотя Visual Studio, я получаю эту ошибку:
Если я вручную попытаюсь удалить файлы в папке bin, в Проводнике Windows, я получаю эту ошибку:
В принципе, все сводится к тому, что MSBuild блокирует файлы (все явно упоминаемые в .tt) в папках bin проектов веб-приложений. Всякий раз, когда проект перестраивается, ссылающиеся DLL снова копируются в собственную папку вывода проекта, и это не удается, поскольку окна не могут перезаписывать файлы, которые "используются".
Единственное, что освобождает блокировку, - это полное закрытие Visual Studio и ее повторное открытие. Я попытался вручную убить все процессы MSBuild на машине или закрыть и снова открыть решение, но ничего не работает. Даже такие инструменты, как Unlocker, не могут удалить блокировку файлов (это даже не обнаруживает).
Исходная проблема на сервере сборки была вызвана той же проблемой, но теперь "решена", потому что я переименовал одну из DLL. Два разных проекта (Mobiltec.Framework.Desktop
и Mobiltec.Framework.WindowsMobile
) имели одинаковое имя dll-вывода (Mobiltec.Framework.dll
), а второе пыталось перезаписать первое в глобальной выходной папке сборки после того, как было выполнено преобразование для .tt(блокировка исходной dll), не выполняющая весь процесс.