Visual Studio 2008 блокирует пользовательские сборки задач MSBuild

Я разрабатываю специальную задачу MSBuild, которая создает уровень ORM, и использую его в проект. Мне мешает поведение Visual Studio, заключающееся в том, чтобы удерживать библиотеки DLL задач MSBuild и не отпускать их.

Я хотел бы организовать свое решение вот так;

My Solution
 |
 +- (1) ORM Layer Custom Task Project
 |  |
 |  +- BuildOrmLayerTask.cs     // here's my task
 |  
 +- (2) Business Logic Project  // and here's the project that uses it.
    |
    +- <UsingTask TaskName="BuildOrmLayerTask" AssemblyFile="$(TaskAssembly)" />

Однако при сборке проекта (2) он фиксируется на сборке из проекта (1). Итак, теперь я не могу снова создать проект (1), не закрывая решение и не открывая его повторно.

Можно ли как-нибудь организовать работу так, чтобы пользовательская задача сборки не блокировалась Visual Studio?


person Steve Cooper    schedule 30.07.2010    source источник


Ответы (3)


(Изменить: Сайед Ибрагим Хашими, который буквально написал книгу на msbuild, предлагает класс AppDomainIsolatedTask для лучшего подхода)

Я сам решил эту проблему ...

Нашел это сообщение на форуме от Дэна Мозли, один из разработчиков MSBuild от Microsoft:

Всем привет,

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

Единственный обходной путь, который я предлагаю, - это вызвать tomsbuild.exe для сборки проектов, использующих эту задачу. Для этого создайте MSBuild.exe ‹> как внешний инструмент в VS.

Дэн
разработчик на msbuild
Дэн Мосли - MSFT

Итак, похоже, чтобы остановить блокировки, вы должны запустить новый процесс MSBuild.exe. Это не может быть тот, который работает внутри Visual Studio, потому что при запуске MSBuild он загружает задачи в основной домен приложения Visual Studio, и это никогда не может быть выгружено.

  • создайте новый проект MSBuild (.csproj или аналогичный), который переопределяет цель «Сборка» и выполняет ваши настраиваемые действия, например;

    <!-- fragment of Prebuild.csproj -->   
    <Target Name="Build">   
         <BuildOrmLayerTask Repository="$(Repository)" />   
    </Target>
    
  • Добавьте его в Visual Studio, если хотите, но используйте Configuration Manager, чтобы убедиться, что он не встроен в какую-либо конфигурацию. Просто позвольте VS позаботиться об управлении исходным кодом и тому подобном, а не о создании.

  • Отредактируйте файл .csproj проекта, который зависит от Prebuild.csproj. Добавьте цель BeforeBuild, которая вызывает MSBuild с помощью задачи Exec. Это запустит новый процесс, и когда этот процесс завершится, блокировки файлов будут сняты. Пример;

    <PropertyGroup>   
         <PrebuildProject>$(SolutionDir)Prebuild\Prebuild.csproj</PrebuildProject>   
    </PropertyGroup>   
    <Target Name="BeforeBuild">   
         <Exec Command="msbuild.exe &quot;$(PrebuildProject)&quot;" />   
    </Target>
    

Теперь, когда вы создаете зависимый проект, он выполняет MSBuild в новом процессе перед запуском компиляции.

person Steve Cooper    schedule 04.08.2010
comment
Запуск другого процесса msbuild.exe кажется единственным работающим решением. Я не понимаю, как расширение AppDomainIsolatedTask должно работать в этой ситуации, поскольку MSBuild уже загрузил сборку в основной домен приложения к тому моменту, когда он пытается прочитать типы. В самом файле проекта должен быть способ указать MSBuild загрузить задачу в другой домен приложений. Microsoft отказывается решать эту серьезную проблему из-за снижения производительности при использовании новых доменов приложений - что ж, давайте переопределим вариант и решим сами? Почему инженеры MS так сложно исправить эту проблему? - person makhdumi; 06.02.2014
comment
Расширение AppDomainIsolatedTask не помогло мне. - person Fosna; 29.09.2014
comment
Вам не нужно создавать отдельный проект MSBuild. Вы можете просто поставить условие на свою цель и заставить цель BeforeBuild выполнить текущий проект с некоторыми параметрами, например <Target Name="TypeLite" Condition="$(ExecuteTypeLite)"> и <Exec Command="&quot;$(MSBuildBinPath)\MSBuild.exe&quot; /t:TypeLite /p:ExecuteTypeLite=true &quot;$(ProjectDir)$(ProjectFileName)&quot;" />. - person user247702; 27.01.2016

Можете ли вы отредактировать файлы проекта и включить следующее объявление свойства

<PropertyGroup>
    <GenerateResourceNeverLockTypeAssemblies>true</GenerateResourceNeverLockTypeAssemblies>
</PropertyGroup>

Сообщите мне, если это сработает для вас.

person Sayed Ibrahim Hashimi    schedule 04.08.2010
comment
Я добавил это во все свои проекты, и теперь он отлично работает. Спасибо! - person Steve Cooper; 04.08.2010
comment
Собственно, когда я начал с ним работать, он снова заблокировался. Но я нашел решение; смотри мой ответ. Кажется, что VS загружает настраиваемые задачи в основной домен приложения, и это никогда не может быть выгружено, поэтому все, что вы можете сделать, это запустить новый процесс MSBuild.exe с помощью Exec. - person Steve Cooper; 04.08.2010
comment
Если это настраиваемая задача, вы можете расширить Microsoft.Build.Utilities.AppDomainIsolatedTask, чтобы помочь вам в этом. - person Sayed Ibrahim Hashimi; 04.08.2010
comment
Я попробовал это, перезапустил Visual Studio, и все работало, пока я не выбрал «Развернуть». Если вы развертываете .dll MSBuild, все равно заблокируйте настраиваемую задачу - person Raffaeu; 06.01.2012
comment
@SayedIbrahimHashimi Не могли бы вы объяснить, как расширение AppDomainIsolatedTask должно работать в этой ситуации? Я могу видеть, как это будет работать, когда сборки, которые вы загружаете в вашу настраиваемую задачу, блокируются, но как это будет работать для сборки, загружаемой самим MSBuild? Разве MSBuild не нужно загружать сборку, прежде чем он увидит, что в ней есть AppDomainIsolatedTasks? Почему не было аналогичной опции с элементом UsingTask? - person makhdumi; 06.02.2014
comment
@ Al-Muhandis После ночного рывка в различных DLL движка сборки с помощью ildasm, я бы сказал, что вы совершенно правы. Сборочная загрузка буквально использует Assembly.Load или Assembly.LoadFrom, в зависимости от того, указали ли вы AssemblyName или AssemblyFile, соответственно, в UsingTask. Кажется, что любая задача, унаследованная от MarshalByRefObject, загружается во вновь созданный домен приложения перед запуском, но обнаружение происходит путем загрузки сборки в домен приложения по умолчанию. Я собираюсь написать задачу-оболочку, чтобы помочь, но ... не сегодня вечером. - person Andrew; 06.07.2014

Как я упоминал в комментарии к @ Al-Muhandis, кажется возможным создать оболочку вокруг настраиваемой задачи, чтобы она блокировалась, но не DLL настраиваемой задачи. Я сделал первый шаг в этом направлении с помощью проекта изолированной задачи. В нем могут быть ошибки, и пока он работает только с VS2008. Запросы на вытягивание приветствуются.

Идея проекта была основана на наблюдении, что задачи, производные от MarshalByRefObject (с использованием, возможно, AppDomainIsolatedTask) кажутся загруженными в основной домен приложения для целей отражения, но новый домен приложения создается для выполнения задачи. Поскольку загрузка в основной домен приложения по-прежнему блокирует DLL, было полезно создать DLL с задачей, производной от AppDomainIsolatedTask, которая загружает библиотеки DLL настраиваемых задач. Таким образом, DLL-оболочка блокируется, но поскольку она выполняется в собственном домене приложения, библиотеки DLL настраиваемых задач выгружаются, когда выгружается домен выполнения задачи-оболочки. Эта процедура позволяет избежать блокировки библиотек DLL настраиваемых задач после завершения сборки.

person Andrew    schedule 10.07.2014