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

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

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

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

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

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

В MyWebProject1 Я добавил ссылку на Project MyBaseProject: "Добавить ссылку..." → вкладка "Проекты" → выберите "MyBaseProject". Свойства этой ссылки те же, кроме следующих элементов:

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

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

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

Я уже убедился, что .csproj MyBaseProject содержит элемент private со значением "true" (это должен быть псевдоним для " скопировать локальный" в Visual Номер-студио):

<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>

(Частный тег по умолчанию не появился в .csproj xml, хотя Visual Studio сказал "скопировать локальный" true. Я переключил "скопировать локальный" на false - сохранен - ​​и снова вернул его в true - save! )

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

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

Ответ 1

Я не уверен, почему это происходит при создании между 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, и, таким образом, не копирует его в каталог проекта Y bin; он копирует только сборки X и A.

Решение

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

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

Лично я предпочитаю вариант 2 по нескольким причинам.

  • Если вы добавите еще один проект в будущем, который ссылается на проект X, вам не нужно будет помнить, чтобы также включать ссылку на сборку B (например, вы должны были бы сделать с вариантом 1).
  • У вас могут быть явные комментарии, говорящие о том, зачем нужен фиктивный код и не удалять его. Поэтому, если кто-то действительно удаляет код случайно (скажем, с помощью инструмента рефакторинга, который ищет неиспользуемый код), вы можете легко видеть из источника управления, что код необходим и его восстановить. Если вы используете параметр 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 assembly and the assembly A get copied to the project 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);
    }

Ответ 2

Я просто разбираюсь в этом так. Перейдите к свойствам вашей справки и сделайте следующее:

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

и что он.

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

Ответ 3

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

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

Ответ 4

Взгляните на:

Этот поток форума MSBuild, который я начал

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

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

Ответ 5

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

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

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

Ответ 6

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

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

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

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

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

Ответ 7

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

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

Ответ 8

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

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

Ответ 9

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

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

Ответ 10

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

Ответ 11

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

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

Ответ 12

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

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

Ответ 13

Использование схемы deadlydog,

Y = > X = > A = > B,

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

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

Ответ 14

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

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

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

Ответ 15

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

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

Ответ 16

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

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

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

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

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

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

Ответ 17

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

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