it-swarm.com.ru

MSBuild не копирует ссылки (файлы DLL) при использовании зависимостей проекта в решении

У меня есть четыре проекта в моем решении Visual Studio (все ориентированы на .NET 3.5) - для моей проблемы важны только эти два:

  1. MyBaseProject <- эта библиотека классов ссылается на сторонний файл DLL (elmah.dll)
  2. MyWebProject1 <- этот проект веб-приложения имеет ссылку на MyBaseProject

Я добавил ссылку elmah.dll в MyBaseProject в Visual studio 2008, нажав «Добавить ссылку ...» → вкладку «Обзор» → выбрав «elmah.dll».

Свойства ссылки Elmah следующие:

  • Псевдонимы - глобальные
  • Копировать локально - true
  • Культура -
  • Описание - Модули и обработчики ошибок (ELMAH) для ASP.NET
  • Тип файла - сборка
  • Путь - D:\webs\otherfolder\_myPath\__ tools\elmah\Elmah.dll
  • Решено - верно
  • Runtime версия - v2.0.50727
  • Указанная версия - false
  • Сильное имя - ложь
  • Версия - 1.0.11211.0

В MyWebProject1 я добавил ссылку на проект MyBaseProject с помощью: «Добавить ссылку ...» → вкладка «Проекты» → выбрав «MyBaseProject». Свойства этой ссылки одинаковы, за исключением следующих элементов:

  • Описание -
  • Путь - D:\webs\CMS\MyBaseProject\bin\Debug\MyBaseProject.dll
  • Версия - 1.0.0.0

Если я запускаю сборку в Visual Studio , файл elmah.dll копируется в мой каталог bin MyWebProject1 вместе с MyBaseProject.dll!

Однако, если я очищаю и запускаю MSBuild для решения (через D:\webs\CMS> C:\WINDOWS\Microsoft.NET\Framework\v3.5\MSBuild.exe/t: ReBuild/p: Configuration = Отладка MyProject.sln) elmah.dll отсутствует в каталоге bin MyWebProject1 - хотя сама сборка не содержит предупреждений или ошибок!

Я уже убедился, что .csproj MyBaseProject содержит элемент private со значением «true» (это должен быть псевдоним для « copy local » в Visual Studio):

<Reference Include="Elmah, Version=1.0.11211.0, Culture=neutral, processorArchitecture=MSIL">
  <SpecificVersion>False</SpecificVersion>
  <HintPath>..\mypath\__tools\elmah\Elmah.dll</HintPath>
    **<Private>true</Private>**
</Reference>

(Закрытый тег не появился в XML-файле .csproj по умолчанию, хотя Visual Studio сказала «копировать локальный» в значение true. Я переключил «копировать локальный» в значение «ложь» - сохранено - и снова установило значение «истина» - сохранить!)

Что не так с MSBuild? Как получить ссылку (elmah.dll), скопированную в корзину MyWebProject1?

Я НЕ хочу добавлять действие копирования после сборки в команду каждого проекта после сборки! (Представьте, что у меня будет много проектов, зависящих от MyBaseProject!)

259
toebens

Я не уверен, почему это отличается при сборке между Visual Studio и MsBuild, но вот что я обнаружил, когда столкнулся с этой проблемой в MsBuild и Visual Studio.

Объяснение

Для примера сценария предположим, что у нас есть проект X, сборка A и сборка B. Сборка A ссылается на сборку B, поэтому проект X включает ссылку как на A, так и на B. Кроме того, проект X включает код, который ссылается на сборку A (например, A. SomeFunction ()). Теперь вы создаете новый проект Y, который ссылается на проект X.

Таким образом, цепочка зависимостей выглядит следующим образом: Y => X => A => B

Visual Studio/MSBuild старается быть умным и привносить в проект Y только те ссылки, которые он обнаруживает как необходимые для проекта X; это делается для того, чтобы избежать загрязнения эталона в проекте Y. Проблема в том, что проект X на самом деле не содержит кода, который явно использует сборку B (например, B.SomeFunction ()), VS/MSBuild не обнаруживает, что требуется B X и, следовательно, не копирует его в каталог bin проекта Y; он только копирует сборки X и A.

Решение

У вас есть два варианта решения этой проблемы, каждый из которых приведет к копированию сборки B в каталог bin проекта Y:

  1. Добавить ссылку на сборку B в проект Y.
  2. Добавьте фиктивный код в файл в проекте X, который использует сборку B.

Лично я предпочитаю вариант 2 по паре причин.

  1. Если в будущем вы добавите еще один проект, который ссылается на проект X, вам не нужно будет также указывать ссылку на сборку B (как это было бы в случае с вариантом 1).
  2. У вас могут быть явные комментарии, говорящие о том, почему фиктивный код должен быть там, а не удалять его. Так что, если кто-то действительно удаляет код случайно (скажем, с помощью инструмента рефакторинга, который ищет неиспользуемый код), вы можете легко увидеть из системы контроля версий, что код требуется, и восстановить его. Если вы используете опцию 1, а кто-то использует инструмент рефакторинга для очистки неиспользуемых ссылок, у вас нет комментариев; вы просто увидите, что ссылка была удалена из файла .csproj.

Вот пример «фиктивного кода», который я обычно добавляю, когда сталкиваюсь с такой ситуацией.

    // DO NOT DELETE THIS CODE UNLESS WE NO LONGER REQUIRE Assembly A!!!
    private void DummyFunctionToMakeSureReferencesGetCopiedProperly_DO_NOT_DELETE_THIS_CODE()
    {
        // Assembly A is used by this file, and that Assembly depends on Assembly B,
        // but this project does not have any code that explicitly references Assembly B. Therefore, when another project references
        // this project, this project's Assembly and the Assembly A get copied to the project's bin directory, but not
        // Assembly B. So in order to get the required Assembly B copied over, we add some dummy code here (that never
        // gets called) that references Assembly B; this will flag VS/MSBuild to copy the required Assembly B over as well.
        var dummyType = typeof(B.SomeClass);
        Console.WriteLine(dummyType.FullName);
    }
141
deadlydog

Я просто так с этим справляюсь. Перейдите в свойства вашей ссылки и сделайте это:

Set "Copy local = false"
Save
Set "Copy local = true"
Save

и это все.

Visual Studio 2010 изначально не ставит: <private>True</private> в ссылочном теге и установка «copy local» в false заставляет его создать тег. После этого он установит его в true и false соответственно.

165
andrew

Если вы не используете сборку непосредственно в коде, тогда Visual Studio, пытаясь быть полезным, обнаруживает, что она не используется, и не включает ее в вывод. Я не уверен, почему вы видите различное поведение между Visual Studio и MSBuild. Вы можете попробовать установить выходные данные сборки для диагностики и сравнить результаты, чтобы увидеть, где они расходятся.

Что касается ссылки на elmah.dll, если вы не ссылаетесь на нее непосредственно в коде, вы можете добавить ее в качестве элемента в свой проект и установить для параметра «Действие сборки» значение Content, а для параметра «Копировать в выходной каталог» значение Always.

38
John Hunter

Взгляни на:

Эту ветку форума MSBuild я начал

Вы найдете мое временное решение/обходной путь там!

(MyBaseProject требуется некоторый код, который ссылается на некоторые классы (что угодно) из elmah.dll для elmah.dll, копируемой в корзину MyWebProject1!)

14
toebens

У меня такая же проблема.

Проверьте, совпадает ли базовая версия вашего проекта с базовой версией библиотеки DLL, на которую вы ссылаетесь.

В моем случае мой клиент был скомпилирован с использованием «Framework 4 Client», а DLL был в «Framework 4».

8
Andre Avelar

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

msbuild.exe myproject.vbproj /T:Rebuild
msbuild.exe myproject.vbproj /T:Package

Это, конечно, означало, что мне не хватало dll-файлов моей библиотеки в bin и, самое главное, в zip-файле пакета. Я нашел это работает отлично:

msbuild.exe myproject.vbproj /T:Rebuild;Package

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

6
vangorra

Как отметил в своем комментарии Алексей Бурцев, все, что используется только в словаре ресурсов XAML, или, в моем случае, все, что используется только в XAML, а не в коде, не считается «используемым» MSBuild. 

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

4
Scott

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

Как только я исправил все ссылки, все работало отлично.

3
Steven Engels

Используя схему deadlydog, 

Y => X => A => B

моя проблема заключалась в том, что когда я собирал Y, сборки (A и B, все 15 из них) из X не показывались в папке bin Y.

Я решил проблему, удалив ссылку X из Y, сохранив, собрав, затем повторно добавив ссылку X (ссылка на проект), и сохранив, собрав, и A и B начали появляться в папке bin Y.

3
J Z

Изменение целевого фреймворка с .NET Framework 4 Client Profile на .NET Framework 4 устранило эту проблему для меня.

Итак, в вашем примере: установите целевой фреймворк на MyWebProject1 в .NET Framework 4

3
Fuyu Persimmon

Для этого необходимо добавить файл .targets в свой проект и настроить его для включения в раздел включений проекта.

Смотрите мой ответ здесь для процедуры.

2
Alex Essilfie

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

Некоторые примеры можно найти в другом посте

2
verbedr

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

2
Spamme

Другой сценарий, в котором это проявляется, - это если вы используете старый тип проекта «Веб-сайт» в Visual Studio. Для этого типа проекта он не может ссылаться на .dll, которые находятся за пределами его собственной структуры каталогов (текущей папки и вниз). Итак, в ответе выше, скажем, ваша структура каталогов выглядит следующим образом:

 enter image description here

Где ProjectX и ProjectY являются родительскими/дочерними каталогами, а ProjectX ссылается на A.dll, которая, в свою очередь, ссылается на B.dll, а B.dll находится за пределами структуры каталогов, например, в пакете Nuget в корневом каталоге (Packages), затем A. DLL будет включен, но B.dll не будет. 

2
Focker

Убедитесь, что оба проекта находятся в одной и той же версии .net, и проверьте локальное свойство copy, но это должно быть true по умолчанию

0
john.kernel

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

У меня есть приложение ASP.NET. Процесс сборки настроен на очистку, а затем сборку.

У меня есть два сценария JenkinsCI . Один для производства и один для постановки. Я развернул свое приложение для постановки, и все работало нормально. Развернуто в рабочей среде и отсутствует файл DLL, на который есть ссылка. Этот DLL файл был просто в корне проекта. Нет в любом репозитории NuGet. DLL было установлено на do not copy.

Скрипт CI и приложение были одинаковыми между двумя развертываниями. После очистки и развертывания в промежуточной среде файл DLL был заменен в месте развертывания приложения ASP.NET (bin/). Это не относится к производственной среде.

Оказывается, в ветке тестирования я добавил шаг в процесс сборки, чтобы скопировать этот файл DLL в каталог bin. Теперь часть, которая заняла некоторое время, чтобы выяснить. Процесс CI не очищался сам. DLL был оставлен в рабочем каталоге и был случайно упакован с файлом ASP.NET .Zip. Производственная ветка никогда не копировала файл DLL таким же образом и никогда не развертывала его случайно.

TLDR; Проверьте и убедитесь, что вы знаете, что делает ваш сервер сборки.

0
Jason Portnoy

Я просто столкнулся с очень похожей проблемой. При компиляции с использованием Visual Studio 2010 файл DLL был включен в папку bin. Но при компиляции с использованием MSBuild сторонний файл DLL не был включен.

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

0
Gary Brunton