Зависимая DLL не копируется в выходную папку сборки в Visual Studio

188

У меня есть визуальное решение для студии. У меня много проектов в решении. Существует один основной проект, который выступает в качестве запуска и использует другие проекты. Есть один проект, скажем "ProjectX". Его ссылка добавлена ​​в основной проект. ProjectX ссылается на другую .NET DLL (скажем, abc.dll), которая не является частью решения.

Теперь эту abc.dll нужно скопировать в папку bin / debug основного проекта, но она там не копируется. Почему это не копируется по каким-либо известным причинам?

Brij
источник
если вы не можете понять это, скопируйте его в ваш prebuild.
Дилшод
как вы используете свой ProjectX в основном проекте - каков тип проекта, цель и т. д.
NSGaga - в основном неактивен
У меня была та же проблема, и этот ответ решил мою проблему: stackoverflow.com/a/8213977/174469
Гордон Такер
есть RestoreProjectStyle доступное решение . Идея состоит в том, чтобы установить <RestoreProjectStyle>PackageReference</RestoreProjectStyle>для каждого проекта .Net Framework в решении.
Олекса

Ответы:

105

Я обнаружил, что если ProjectX ссылается на abc.dll, но напрямую не использует какой-либо из типов DEFINED в abc.dll, то abc.dll НЕ будет скопирован в основную выходную папку. (Это будет скопировано в выходную папку ProjectX, чтобы сделать его более запутанным.)

Итак, если вы явно не используете какой-либо из типов из abc.dll где-либо в ProjectX, поместите фиктивное объявление где-нибудь в один из файлов в ProjectX.

AbcDll.AnyClass dummy006; // this will be enough to cause the DLL to be copied

Вам не нужно делать это для каждого класса - достаточно одного раза, чтобы сделать копию DLL, и все будет работать как положено.

Приложение: Обратите внимание, что это может работать для режима отладки, но НЕ для выпуска. Подробности смотрите в ответе @ nvirth.

Повелитель Цург
источник
7
Это похоже на взлом. Добавление ссылки на основной проект кажется достаточным.
Майк К
3
Это взлом, но, как научили нас сегодняшние новости CodeProject, даже компиляторы могут ошибаться!
Повелитель Цург
4
Как безумные вещи могут быть. @OverlordZurg ваше решение сработало, так как у меня была ссылка на зависимую dll в моем XAML (WPF), и она не копировала DLL в основной проект, пока я не добавил простую фиктивную ссылку, как вы сказали ... В любом случае, спасибо
Мохсен Афшин
5
@ MohsenAfshin У меня была та же проблема - я ссылался на зависимую DLL в XAML. Однако вместо объявления фиктивной переменной я просто назвал компонент, который использовал в XAML, и этого было достаточно, чтобы скопировать его сборку.
Redcurry
5
@MikeK Добавление его в основной проект (который на самом деле напрямую не зависит от него) - еще один хак, imo. Тогда вам придется управлять им двумя местами («управлять» как при обновлении или удалении). С этим хаком, по крайней мере, вы получите приятную ошибку во время компиляции, напоминающую вам об удалении этого хака при удалении зависимости, и вам все равно нужно будет обновить его только в одном месте.
jpmc26
71

Просто знаком с ответом Повелителя Зурга.

Я добавил фиктивную ссылку таким образом, и она работала в режиме отладки:

public class DummyClass
{
    private static void Dummy()
    {
        var dummy = typeof(AbcDll.AnyClass);
    }
}

Но в режиме Release зависимая DLL все равно не была скопирована.
Это сработало однако:

public class DummyClass
{
    private static void Dummy()
    {
        Action<Type> noop = _ => {};
        var dummy = typeof(AbcDll.AnyClass);
        noop(dummy);
    }
}

Эта информация фактически стоила мне часов, чтобы понять, поэтому я решил поделиться ею.

nvirth
источник
7
в режиме релиза оптимизатор предполагает, что «пустышка» не используется, поэтому эта строка не нужна и должна быть удалена. но когда вы используете «пустышку» в коде, оптимизатор не считает это ненужным.
Юсель
1
это не работает для меня. AbcDll.AnyClass по-прежнему не копируется в другой проект
Мэтью Локк
3
Убедитесь, что AbcDll.AnyClassоно используется в качестве открытого поля или свойства для открытого класса, тогда оно будет работать. Если вы используете его в теле метода, подобного этому, компилятор не увидит его . Это задержит загрузку этой сборки, а не то, что вы хотите, чтобы произошло.
Джон Лейдгрен
52

Да, вам нужно установить Copy Localна true. Тем не менее, я почти уверен, что вам также нужно сослаться на эту сборку из основного проекта и установить Copy Localее true- она ​​не просто копируется из зависимой сборки.

Вы можете добраться до Copy Localсобственности, нажав на сборку под Referencesи нажав F4.

Майк Перренуд
источник
2
@Brij, на сборку ссылаются из основного проекта, в котором вы хотите ее видеть ? Как я уже говорил, я почти уверен, что вам нужно ссылаться и на этот проект - зависимые сборки не копируются таким образом. Если бы это было так, вам не нужно было бы добавлять сборки во все соответствующие проекты при использовании NuGet.
Майк Перреноуд
1
какой был вывод здесь? Мне кажется, что вы правы - зависимые ссылки не копируются, даже если для CopyLocal установлено значение true - какая логика стоит за этим?
mcmillab
29
@mcmillab, короче говоря, Visual Studio не выводит зависимости от других зависимых проектов. Если проект A ссылается на проект B, проект A должен иметь все ссылки на проект B. Он хорошо работает, когда все, что требуется для проекта B, - это сборки .NET, но если это сборка стороннего производителя, необходимо добавить ссылку на оба проекта.
Майк Перрено
12
@MichaelPerrenoud Не думаю, что это правда. Если вы посмотрите подробный вывод MSBuild, то увидите вызовы ResolveAssemblyReference, в которых говорится, что он «включает зависимости второго и n-го порядка». Это также согласуется с тем, что я вижу в моих папках bin (копируются n-ые зависимости). Проблема в том, что есть некоторые предостережения относительно того, что копируется, в основном в отношении GAC и косвенных ссылок (добавить ссылку иногда недостаточно)
Джек Уклея,
2
Мой текущий опыт заключается в том, что это будет работать за исключением «скопированных» зависимостей: проект A.net ссылается на внешние библиотеки C ++ как файлы, которые «всегда копируются». Ссылки на проект B.net Проект A. В сборке B / Debug включает библиотеки C ++. Однако, когда я собираю Приложение X, которое ссылается на Проект B, библиотеки C ++ иногда копируются (кажется, только если я делаю Перестройку).
Бенджол
34

Это выглядит гладко, когда вы делаете его атрибутом сборки

[AttributeUsage(AttributeTargets.Assembly)]
public class ForceAssemblyReference: Attribute
{        
    public ForceAssemblyReference(Type forcedType)
    {
        //not sure if these two lines are required since 
        //the type is passed to constructor as parameter, 
        //thus effectively being used
        Action<Type> noop = _ => { };
        noop(forcedType);
    }
}

Использование будет:

[assembly: ForceAssemblyReference(typeof(AbcDll.AnyClass))]
Арье Радле
источник
Спасибо, но для меня это что-то делает, только когда я добавляю атрибут сборки в зависимость (Project X), который уже ссылается на AbcDll.AnyClass. И потом, он не делает больше, чем обычно, где он копирует AbcDll в выходной каталог зависимости. Он все еще не копирует его в вывод основного зависимого проекта. И я не могу добавить атрибут в зависимую сборку, пока не добавлю ссылку на AbcDll. Когда я это делаю, AbcDll уже копируется без атрибута.
JS
25

Столкнулся с этой же проблемой. Справочная информация: перед сборкой я добавил новый проект X в решение. Проект Y зависел от проекта X, а проект A, B, C зависел от проекта Y.

Ошибки сборки были в том, что dll проектов A, B, C, Y и X не могли быть найдены.

Основная причина заключалась в том, что недавно созданный Project X был нацелен на .NET 4.5, а остальные проекты решений нацелены на .NET 4.5.1. Проект X не создавался, в результате чего остальные проекты тоже не создавались.

Убедитесь, что все новые добавленные проекты нацелены на ту же версию .NET, что и остальная часть решения.

Даррен Альфонсо
источник
1
Указанные проекты могут быть более старой версией .NET. Я могу ссылаться на проект, созданный для .NET 4 с помощью проекта, созданного для .NET 4.5.
Redcurry
18

Не уверен, что это поможет, но для меня, много раз я ссылаюсь на DLL (которая автоматически добавляет ее в папку bin). Однако эта DLL может потребоваться дополнительные библиотеки DLL (в зависимости от того, какие функции я использую). Я НЕ хочу ссылаться на них в моем проекте, потому что они просто должны оказаться в той же папке, что и библиотека, которую я на самом деле использую.

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

Затем измените свойства этого файла на ...

Build Action = None (если этот параметр установлен на что-то вроде Content, фактически копируется «корневая» версия в корень плюс копия в корзине).

Копировать в выходную папку = Копировать, если новее (в основном помещает его в папку BIN, только если он отсутствует, но не делает этого после этого)

Когда я публикую .. мои добавленные DLL существуют только в папке BIN и больше нигде в месте публикации (что я и хочу).

da_jokker
источник
10

Вы также можете убедиться, что искомые DLL не включены в GAC. Я считаю, что Visual Studio умело не копирует эти файлы, если они уже существуют в GAC на компьютере сборки.

Недавно я столкнулся с такой ситуацией, когда я тестировал пакет служб SSIS, для которого нужны сборки в GAC. С тех пор я забыл об этом и удивлялся, почему эти библиотеки не появлялись во время сборки.

Чтобы проверить, что находится в GAC (из командной строки разработчика Visual Studio):

gacutil -l

Или вывод в файл, чтобы его было легче читать:

gacutil -l > output.txt
notepad.exe output.txt

Чтобы удалить сборку:

gacutil -u MyProjectAssemblyName

Следует также отметить, что после удаления файлов из GAC они правильно выводились в каталог \ bin после сборки (даже для сборок, на которые нет прямой ссылки в корневом проекте). Это было в Visual Studio 2013, обновление 5.

Brett
источник
Спасибо, вы правы, MSBuild не будет копировать dll в выходную папку, если обнаружит их в GAC.
Джон-Филипп
3

В моем случае это была самая глупая вещь, вызванная поведением TFS / VS по умолчанию, с которым я не согласен.

Поскольку добавление dll в качестве ссылки на основной проект не сработало, я решил добавить его в качестве «Существующего элемента» с Copy Local = Always. Даже тогда файла там не было.

Оказывается, что, хотя файл присутствует в решении VS и все скомпилировано как локально, так и на сервере, VS / TFS фактически не добавлял файл в систему контроля версий. Он не был включен в «Ожидающие изменения» вообще. Мне пришлось вручную перейти в Source Control Explorer и явно нажать на значок «Добавить элементы в папку».

Глупо, потому что я 15 лет развиваюсь в VS. Я сталкивался с этим раньше, я просто не запомнил и почему-то пропустил это, потому что все по-прежнему компилировалось из-за того, что файл являлся обычной ссылкой, но файл, который был добавлен как существующий элемент, не копировался, потому что он не существовал на сервер контроля версий.

Надеюсь, это сэкономит кому-то время, так как я потерял 2 дня своей жизни на это.

GR7
источник
1
Я не могу отблагодарить тебя достаточно ... ты сэкономил мне столько времени. Это было решением для меня. Это также выявило проблему с корнем, DLL, которую я добавил в качестве ссылки, соответствовал gitignoreшаблону, поэтому при добавлении в качестве ссылки он не добавлялся в проект. Вы ДОЛЖНЫ вручную добавить файл в систему контроля версий !!!
Mattkwish
2

Это небольшой твик на примере nvirth

internal class DummyClass
{
    private static void Dummy()
    {
        Noop(typeof(AbcDll.AnyClass));
    }
    private static void Noop(Type _) { }
}
maca134
источник
2

Я бы добавил его в события Postbuild, чтобы скопировать необходимые библиотеки в выходные каталоги. Что-то вроде директории путевых библиотек XCopy

Вы можете найти их в свойствах проекта -> Build Events.

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

Выпуск:

Обнаружена похожая проблема для библиотеки DLL пакета NuGet (Newtonsoft.json.dll), в которой выходные данные сборки не содержат ссылочную библиотеку DLL. Но сборка идет хорошо.

Fix:

Просматривайте свои проекты в текстовом редакторе и ищите ссылки с тегами в них. Как Истина или Ложь. «Private» - это синоним «Copy Local». Где-то в действиях MSBuild пытается найти зависимости, он находит вашу зависимость где-то еще и решает не копировать ее.

Итак, просмотрите каждый файл .csproj / .vbproj и удалите теги вручную. Перестройте, и все работает как в Visual Studio, так и в MSBuild. Как только у вас это заработает, вы можете вернуться и обновить то, что, по вашему мнению, должно быть.

Ссылка:

https://www.paraesthesia.com/archive/2008/02/13/what-to-do-if-copy-local-works-in-vs-but.aspx/

Нкл кумар
источник
1

НЕТ НЕОБХОДИМОСТИ манекена КОДА
Just:

добавить ссылку на исполняемый проект

или / и убедитесь, что ссылка в исполняемом проекте "Copy Local"установлена TRUE(что было моей « ошибкой »), похоже, что это «перезаписало» настройку в базовом ссылочном проекте библиотеки ...

Cadburry
источник
1

Если вы щелкнете правой кнопкой мыши по указанной сборке, вы увидите свойство с именем Copy Local . Если для параметра Копировать локально задано значение true, сборка должна быть включена в корзину. Тем не менее , есть проблемы с Visual Studio, которые иногда не включают DLL-библиотеку, на которую ссылаются, в папке bin ... Это обходной путь, который работал для меня:

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

Хуман Бахрейни
источник
1
Копирование Loal было отключено, это помогло stackoverflow.com/questions/15526491/…
codemirror
1

TLDR; Visual Studio 2019 может просто потребоваться перезагрузка.

Я столкнулся с этой ситуацией, используя проекты на основе проекта Microsoft.NET.Sdk.

<Project Sdk="Microsoft.NET.Sdk">

В частности:

  • Project1: цели .netstandard2.1
    • ссылки Microsoft.Extensions.Logging.Consoleчерез Nuget
  • Project2: цели .netstandard2.1
    • ссылки Project1через ссылку проекта
  • Project2Tests: цели .netcoreapp3.1
    • ссылки Project2через ссылку проекта

При выполнении теста я получил сообщение об ошибке, указывающее, что Microsoft.Extensions.Logging.Consoleне может быть найдено, и оно действительно не было в выходном каталоге.

Я решил обойти эту проблему, добавив Microsoft.Extensions.Logging.Consoleв Project2, только чтобы обнаружить, что диспетчер Nuget в Visual Studio не выводит список Microsoft.Extensions.Logging.Consoleустановленных в нем Project1, несмотря на то, что он присутствует в Project1.csprojфайле.

Простое завершение работы и перезапуск Visual Studio решили проблему без необходимости добавления дополнительной ссылки. Возможно, это сэкономит кому-то 45 минут потерянной производительности :-)

Эрик Патрик
источник
На самом деле я перезагружал весь ПК, когда проводил тестирование, но у меня это
получалось
0

Вы можете установить как основной проект, так и путь вывода сборки ProjectX в одну и ту же папку, затем вы можете получить все необходимые библиотеки в этой папке.

YantingChen
источник
0

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

Вы можете проверить это, выбрав свой проект, затем нажмите ALT + ENTER, затем выберите Приложение слева и затем выберите Target Framework вашего проекта.

Предположим, что зависимая целевая платформа dll = 4.0 и целевая платформа приложения dll = 3.5, затем измените ее на 4.0

Спасибо!

Маниш джайн
источник
0

Помимо общих вышеупомянутых, у меня было многопроектное решение для публикации. Видимо, некоторые файлы предназначены для разных структур.

Итак, мое решение: Свойства> Конкретная версия (False)

RicL
источник
0

Добавьте DLL как существующий элемент в один из проектов, и он должен быть отсортирован

abhijithkarkal
источник
0

VS2019 V16.6.3

Для меня проблема заключалась в том, что основной файл .proj заканчивался такой записью для проекта, DLL которого не копировалась в папку bin родительского проекта:

<ProjectReference Include="Project B.csproj">
  <Project>{blah blah}</Project>
  <Name>Project B</Name>
  <Private>True</Private>
</ProjectReference>

Я вручную удалил строку, <Private>True</Private>а затем DLL была скопирована в папку bin основного проекта при каждой сборке основного проекта.

Если вы перейдете к ссылке на проблемный проект в папке ссылок основного проекта, щелкните по ней и просмотрите свойства, там есть параметр «Копировать локальный». Закрытый тег соответствует этому параметру, но для меня по какой-то причине изменение локальной копии не оказало влияния на закрытый тег в файле .proj.

Досадно, что я не изменил локальное значение копии для ссылки, понятия не имею, как он был настроен таким образом, и потратил еще один день на поиск глупой проблемы с VS.

Благодаря всем остальным ответам, которые помогли мне разобраться в причинах.

НТН

Ричард Мур
источник