2010-07-30 2 views
25

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

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

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?

ответ

21

(Edit:Sayed Ibrahim Hashimi, который буквально wrote the book на MSBuild, предлагает AppDomainIsolatedTask класс для лучшего подхода)

мне удалось решить эту один я ...

Нашел forum post from Dan Moseley, один из разработчиков MSBuild от Microsoft:

Привет,

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

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

Dan
разработчик на MSBuild
DanMoseley - MSFT

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

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

    <!-- fragment of Prebuild.csproj --> 
    <Target Name="Build"> 
        <BuildOrmLayerTask Repository="$(Repository)" /> 
    </Target> 
    
  • Добавьте его в визуальной студии, если вы хотите, но использовать 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 в новом процессе перед запуском компиляции.

+2

Запуск другого процесса msbuild.exe, по-видимому, является единственным решением, которое работает. Я не вижу, как расширение AppDomainIsolatedTask должно работать в этой ситуации, поскольку MSBuild уже загрузил сборку в основной AppDomain к моменту, когда он пытается прочитать типы. В самом файле проекта должен быть способ сообщить MSBuild о загрузке задачи в другой AppDomain. Microsoft отказывается исправить эту серьезную проблему из-за производительности с использованием новых AppDomains - хорошо, давайте переопределим опцию и решим для себя? Почему такая сложная проблема для MS «инженеров» исправить? – makhdumi

+1

Расширение AppDomainIsolatedTask не работает для меня. – Fosna

+1

Вам не нужно создавать отдельный проект MSBuild. Вы можете просто поставить условие на свою цель и сделать цель «BeforeBuild» выполнить текущий проект с некоторыми параметрами, например. '' и ''. – Stijn

4

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

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

Позвольте мне знать, если это работает для вас.

+0

Я добавил это ко всем моим проектам, и теперь он отлично работает. Благодаря! –

+0

На самом деле, когда я начал работать с ним, он снова заперся. Однако я нашел решение; см. мой ответ. Похоже, что VS загружает пользовательские задачи в основной домен приложения и никогда не может быть выгружен, поэтому все, что вы можете сделать, это запустить новый процесс MSBuild.exe с помощью Exec. –

+8

Если это настраиваемая задача, вы можете расширить Microsoft.Build.Utilities.AppDomainIsolatedTask, чтобы помочь вам в этом. –

3

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

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