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

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

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

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

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

  • Псевдонимы - глобальные
  • Копировать локально - правда
  • Культура -
  • Описание - Модули и обработчики ошибок (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 = Debug MyProject.sln ) elmah.dll отсутствует в каталоге bin MyWebProject1 - хотя сама сборка не содержит предупреждений или ошибок!

Я уже убедился, что .csproj MyBaseProject содержит закрытый элемент со значением «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!)

15.07.2009 15:46:08
Я хотел бы получить более четкий ответ, почему это происходит.
David Faivre 27.04.2012 17:18:23
Посмотрите на ответ, приведенный здесь
Anuroopa Shenoy 22.08.2012 15:31:50
какое-нибудь окончательное решение с полным примером исходного кода работает над этим?
Kiquenet 13.05.2013 14:24:37
См. Ответ stackoverflow.com/a/21055664/21579 ниже @deadlydog. Отличное объяснение и решенный вопрос для меня ... самый голосующий ответ ниже не является правильным для VS2012.
Jeff Widmer 8.05.2014 14:29:37
Zack 8.06.2017 20:41:38
19 ОТВЕТОВ
РЕШЕНИЕ

Я не уверен, почему это отличается при сборке между 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);
    }
151
19.01.2016 16:37:09
Здесь не обсуждается то, что существует разница между копированием продуктов сборки в / bin веб-проекта и обычным копированием в целевой выходной каталог (например, / bin / x86 / Debug). Первый выполняется ссылочным проектом при сборке, а второй - зависимым веб-проектом. Изучение Microsoft.Common.targets помогает понять это. Копии в web / bin вообще не зависят от локального поведения копирования - копируйте локальные воздействия на копию в выходной целевой каталог, который не является частью структуры, на которую ссылается Cassini, работающий через Debug.
user1164178 18.07.2014 04:55:31
Вы можете объяснить, почему он работал с VS БЕЗ добавления этого "фиктивного кода", но не с msbuild?
toebens 25.02.2015 20:54:14
Даже менее инвазивный, чем вызов функции, вы можете назначить тип класса, содержащегося в сборке, фиктивной переменной. Type dummyType = typeof(AssemblyA.AnyClass);
Arithmomaniac 16.03.2015 14:50:29
Решение № 2, как показано выше, будет работать, если в Visual Studio не установлен флажок «Оптимизировать код». В этом случае он все равно будет исключать DLL. Я добавил еще одну строку, чтобы отменить ее «оптимизацию». Console.WriteLine(dummyType.FullName);
JasonG 24.07.2015 20:22:24
Решение 2 не работало для меня в Visual Studio 2017. Сначала я подумал, что это потому, что в моей сборке X я использовал только оператор enumfrom B и предположил, что enum вставляется. Я добавил код, чтобы напрямую использовать тип из B, и это не помогло. Также всегда было так, что my X использует типы в A, которые подклассируют типы в B, поэтому я не могу понять, как компилятор считает, что B не требуется X и может быть проигнорировано. Это помешанные.
Xharlie 25.04.2017 12:18:44

Взгляни на:

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

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

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

14
20.01.2017 17:57:19
Черт возьми - это единственное решение, к которому я тоже пришел - надеялся, что может быть лучший способ сделать это!
nickspoon 22.08.2013 22:06:59
Смотрите ответ Эндрю ниже для менее хакерского решения (без обид!)
MPritchard 31.10.2013 16:26:52
Для тех, кто смотрит на это сейчас, ответ toebens на MSDN по сути такой же, как и ответ Deadlydog , предоставленный спустя несколько лет.
jpaugh 18.12.2018 16:30:14

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

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

38
20.01.2017 17:58:18
+1 для вашей копии в комментарии к выходному каталогу, если Elmah не используется в коде, имеет смысл копировать как контент.
Kit Roed 26.07.2010 17:00:14
Действительно, он игнорирует сборки, которые не используются, НО одну важную вещь, чтобы отметить, что в VS 2010 использование сборок в словарях ресурсов XAML не рассматривается как использование ассемблера VS, поэтому он не будет копировать его.
Alex Burtsev 8.10.2011 05:54:46
Это лучше для проекта модульного тестирования, где мне нужна DLL. Я не хочу добавлять dll, который не нужен основному проекту только для запуска тестов!
Lukos 7.06.2018 12:32:26

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

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

и это все.

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

170
21.10.2011 23:54:33
Это была находка. Спасибо тебе за это!
Rebecca 21.11.2011 15:09:17
Не работал для меня с MSBuild 4 / VS2012. То есть я смог обновить ссылки, чтобы сказать, <Private>true</Private>но это, похоже, не влияло на MSBuild. В конце я просто добавил ссылки NuGet на проекты нижнего уровня.
Michael Teper 18.01.2013 21:48:33
Не работал для меня Он все еще не копирует System.Net.Http.Formatting в папку bin.
Akira Yamamoto 8.11.2013 16:25:03
Это эквивалентно Have you tried turning it off and on again?, и это сработало!
guanome 18.06.2014 20:52:33
Похоже, что VS2015 по-прежнему ведет себя так же: установка «Локальное копирование» на «Ложь» и затем «Истина» для указанных DLL-файлов работает.
flip 23.08.2015 04:59:53

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

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

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

8
25.06.2012 08:22:42

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

2
27.06.2012 09:39:57

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

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

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

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

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

6
18.07.2012 22:49:52
У меня была та же проблема, которая заключалась в построении целого решения с использованием / t: Build из TeamCity за один шаг, а затем в следующем проекте / t: Package on WebAPI. Все библиотеки, на которые ссылаются любые ссылки на проекты, не были включены. Это было исправлено с помощью вышеупомянутого - / T: Rebuild; пакет в WebAPI затем включал эти библиотеки.
Andy Hoyle 21.09.2017 09:43:43

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

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

-1
20.01.2017 18:00:51
Это дубликат верхнего ответа.
Giles Roberts 27.11.2019 16:38:02

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

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

3
2.08.2013 19:20:50

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

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

4
20.01.2017 18:01:56
Это была именно моя проблема и решение, которое сработало. Потратил слишком много времени, пытаясь понять это. Спасибо Скотт & @
karol 3.08.2016 15:57:36
Боже мой, это сводило меня с ума. Да , я использовал FontAwesome.WPF и только из XAML (по понятным причинам). Добавление фиктивного метода помогло. Спасибо! И да, VS 2017 все еще подвержен влиянию 15.6, поэтому я подал ошибку: github.com/dotnet/roslyn/issues/25349
Sören Kuklau 8.03.2018 18:32:25

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

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

2
23.05.2017 11:54:44

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

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

2
23.05.2017 12:10:36

Включение всех ссылочных DLL-файлов из ваших проектных ссылок в проект Website - не всегда хорошая идея, особенно когда вы используете внедрение зависимостей : ваш веб-проект просто хочет добавить ссылку на интерфейсный файл / проект DLL, а не какую-либо конкретную реализацию DLL файл.

Потому что, если вы добавите ссылку непосредственно к файлу / проекту реализации DLL, вы не сможете помешать своему разработчику вызывать «новый» для конкретных классов файла / проекта реализации DLL, а не через интерфейс. Также вы указали «жесткий код» на вашем сайте, чтобы использовать реализацию.

-3
20.01.2017 18:03:31

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

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

5
12.02.2014 15:24:53

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

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

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

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

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

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

0
20.01.2017 18:06:05

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

Y => X => A => B ,

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

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

3
8.12.2016 20:39:56
После многих часов поиска и опробования многих других решений это сработало для меня.
Suncat2000 3.03.2017 13:15:19

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

введите описание изображения здесь

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

2
20.03.2017 18:19:29

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

0
8.02.2019 08:08:51

Используя Visual Studio 2015 добавление дополнительного параметра

/ Deployonbuild = ложь

в командной строке msbuild исправлена ​​проблема.

0
27.11.2019 16:40:22