Залежна DLL не копіюється у папку виводу збірки у Visual Studio


188

У мене є візуальне рішення студії. У мене багато проектів у вирішенні. Є один головний проект, який виступає як старт, і використовує інші проекти. Є один проект сказати "ProjectX". Його посилання додається до основного проекту. ProjectX посилається на інший .NET dll (скажімо, abc.dll), який не є частиною рішення.

Тепер цей abc.dll повинен бути скопійований у папку bin / debug основного проекту, але він там не копіюється. Чому це не скопійовано з відомих причин?


якщо ви не можете цього зрозуміти, скопіюйте його у попередній збір.
Dilshod

як ти використовуєш "ProjectX" у головному проекті - який тип проекту, ціль тощо
NSGaga - здебільшого неактивний

У мене було те саме питання, і ця відповідь вирішила мою проблему: stackoverflow.com/a/8213977/174469
Гордон Такер


є RestoreProjectStyle рішення . Ідея полягає у встановленні <RestoreProjectStyle>PackageReference</RestoreProjectStyle>для кожного проекту .Net Framework у рішенні.
олекса

Відповіді:


105

Я виявив, що якщо ProjectX посилався на abc.dll, але безпосередньо не використовував жодного з типів, визначених у 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 в основний проект, поки я не додав просту макетну посилання, як ви сказали ... Спасибі все одно
Mohsen Afshin

5
@MohsenAfshin У мене була така ж проблема --- я посилався на залежну DLL в XAML. Замість того, щоб оголосити фіктивну змінну, я просто назвав компонент, який я використовував у XAML, і цього було достатньо, щоб змусити скопіювати його збірку.
redcurry

5
@MikeK Додавання його до основного проекту (який насправді не залежить безпосередньо від нього) - це ще більший хак, imo. Тоді вам доведеться керувати ним двома місцями ("керувати", як при оновленні чи видаленні). За допомогою цього злому ви отримуєте приємну помилку часу компіляції, що нагадує вам видалити цей хак, коли ви видалите залежність, і вам потрібно лише оновити його в одному місці.
jpmc26

71

Лише стороною відповіді на відповідь Overlord Zurg.

Я додав посилання на манекен таким чином, і він працював у режимі налагодження:

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

Але в режимі випуску залежний dll все ще не скопіювався.
Однак це спрацювало:

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

Ця інформація фактично коштувала мені годин, щоб розібратися, тому я подумав, що поділяюсь цим.


7
в режимі випуску оптимізатор припускає, що "манекен" не використовується, тому цей рядок є непотрібним і його слід видалити. але коли ви використовуєте "фіктивний" код, оптимізатор не вважає його зайвим.
Юцель

1
це не працює для мене.AbcDll.AnyClass досі не скопійовано в інший проект
Matthew Lock

3
Переконайтеся, що AbcDll.AnyClassвін використовується як публічне поле або властивість для публічного класу, тоді він спрацює. Якщо ви використовуєте його в тілі методу, як цей, компілятор не бачить його . Це затримає завантаження цієї збірки, а не те, що ви хочете статися.
Джон Лейдегрен

52

Так, вам потрібно встановити Copy Localна true. Однак я впевнений, що вам також потрібно посилатися на цю збірку з головного проекту і налаштовувати Copy Localнаtrue неї - вона не просто копіюється з залежної збірки.

Ви можете дістатися до Copy Localоб'єкта, натиснувши на збірку під Referencesта натиснувши F4.


2
@Brij, це посилання на основний проект, на який ви хочете? Як я вже зазначив, я впевнений, що вам потрібно посилатися на цей проект, оскільки залежні збірки не копіюються так. У такому разі вам не потрібно буде додавати збірки до всіх відповідних проектів при використанні NuGet.
Майк Перренод

1
про що тут був висновок? Мені здається, що ви не залежать від прав, посилання яких не копіюються, навіть якщо CopyLocal встановлено на істинне - яка логіка в цьому?
mcmillab

29
@mcmillab, коротше Visual Studio НЕ робити висновок залежностей від інших залежних проектів. Якщо проект A посилається на проект B, проект A повинен мати всі посилання проекту B. Це добре працює, коли всі проекти B потребують .NET збірок, але якщо це сторона-збори, ви повинні додати посилання на обидва проекти.
Майк Перренод

12
@MichaelPerrenoud Я не думаю, що це правда. Якщо ви подивитесь на детальний вихід MSBuild, ви побачите виклики ResolveAssemblyReference, де зазначено, що "включає залежності другого та n-го порядку". Це також узгоджується з тим, що я бачу у своїх бін папках (n-ї залежності копіюються). Проблема полягає в тому, що є кілька застережень щодо того, що скопійовано, в основному навколо GAC та непрямих посилань (Додати довідку іноді недостатньо)
Jack Ukleja

2
Мій сучасний досвід полягає в тому, що це спрацює за винятком "скопійованих" залежностей: проект A.net згадує зовнішні C ++ dll як файли, які "копіюються завжди". Посилання на проект B.net Проект А. Під час збирання B / Debug включає С ++. Однак, коли я будую додаток X, на який посилається Project B, місцями C ++ іноді копіюється (здається, лише якщо я буду відновлювати).
Benjol

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

Побіг у цьому ж питанні. Довідкова інформація: перед тим як будувати, я додав у рішення новий Project X. Проект Y залежав від проекту X, а проект A, B, C залежав від проекту Y.

Помилки побудови полягали у тому, що не вдалося знайти dll Project 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 (що автоматично додає його до папки бін). Однак DLL можуть знадобитися додаткові DLL (залежно від того, які функції я використовую). Я НЕ хочу посилатися на тих, хто знаходиться в моєму Проекті, тому що їм просто потрібно опинитися в тій же папці, що і DLL, яку я фактично використовую.

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

Потім змініть властивості цього файлу на ...

Build Action = None (встановлення цього параметра на зразок вмісту насправді копіює "root" версію в корінь плюс копію у кошику).

Копіювати у вивідну папку = Копіювати, якщо новіше (В основному поміщає її у папку BIN, лише якщо вона відсутня, але після цього не робиться)

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


10

Ви також можете перевірити, чи DLL-файли, які ви шукаєте, не включені в GAC. Я вважаю, що Visual Studio розумно не копіює ці файли, якщо вони вже є в GAC на машині збирання.

Я нещодавно зіткнувся з цією ситуацією, коли я тестував пакет SSIS, який потребував збірок, щоб існувати в GAC. З тих пір я це забув і цікавився, чому ці DLL-файли не виходили під час збирання.

Щоб перевірити, що знаходиться в GAC (з командного рядка для розробників Visual Studio):

gacutil -l

Або виведіть у файл, щоб полегшити читання:

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

Щоб видалити збірку:

gacutil -u MyProjectAssemblyName

Я також повинен зазначити, що після того, як я видалив файли з GAC, вони були правильно виведені в каталог \ bin після збірки (Навіть для збірок, на які безпосередньо не посилалося в кореневому проекті). Це було в Visual Studio 2013 Update 5.


Дякую, ви праві, MSBuild не буде копіювати dll у папку виводу, якщо вона знайшла їх у GAC.
Джон-Філіп

3

У моєму випадку це була найглупіша річ, викликана поведінкою TFS / VS за замовчуванням, з якою я не згоден.

Оскільки додавання dll як посилання на основний проект не спрацювало, я вирішив додати його як "Існуючий предмет", з Copy Local = Завжди. Вже тоді файлу там не було.

Виявляється, незважаючи на те, що файл присутній у VS Solution та все, складене як локально, так і на сервері, VS / TFS не додав фактично додавання файлу до керування джерелом. Вона взагалі не була включена до "Очікує на зміну". Мені довелося вручну перейти до «Провідника управління джерелами» та явно натиснути на значок «Додати елементи в папку».

Дурний, бо я вже 15 років розвиваюся в VS. Я раніше стикався з цим, я просто не пам’ятав, і я якось пропустив це, тому що все ще компілюється через те, що файл є регулярною посиланням, але файл, доданий як існуючий елемент, не копіювався, оскільки його не існувало на сервер управління джерелом.

Я сподіваюся, що це економить когось деякий час, оскільки я втратив на це 2 дні свого життя.


1
Я не можу вам подякувати достатньо ... ти врятував мені стільки часу. Це було рішенням для мене. Він також виявив кореневу проблему, DLL, який я додав у якості посилання, відповідав gitignoreшаблону, тому при додаванні в якості посилання він не додавав проект. Ви МОЖЕТЕ вручну додати файл до керування джерелом !!!
Метквіш

2

Це невеликий твіст на прикладі nvirth

internal class DummyClass
{
    private static void Dummy()
    {
        Noop(typeof(AbcDll.AnyClass));
    }
    private static void Noop(Type _) { }
}

2

Я б додав його до подій Postbuild, щоб скопіювати необхідні бібліотеки у вихідні каталоги. Щось на зразок XCopy шляхотехнічних бібліотек targetdirectory

Ви можете знайти їх у властивостях проекту -> Створення подій.


Це працювало для мене, і я думаю, що це краща відповідь. Референтне рішення-манекен працює, але це хак, тоді як правило після складання - чистий спосіб досягти того ж результату.
Кевін Фіхтер

2

Проблема:

Зустрічався з аналогічною проблемою для пакета DLL NuGet (Newtonsoft.json.dll), де вихід збірки не включає посилання DLL. Але збірка проходить чудово.

Виправити:

Перегляньте свої проекти в текстовому редакторі та шукайте посилання з тегами в них. Як Правда чи Неправда. "Приватне" є синонімом "Копіювати місцеве". Десь у своїх діях 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

НЕ ПОТРІБНА ДУМКА У КОДІ
Просто:

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

або / і переконайтеся, що посилання у виконаному проекті "Copy Local"встановлено на TRUE(що було моєю " помилкою "), здається, що це "перекреслило" налаштування в базовій бібліотеці-проекті, на яку посилається ...


1

Якщо ви праві, натисніть на посилання, на яке посилається, ви побачите властивість під назвою Copy Local . Якщо для параметра Copy Local встановлено значення true, збірка повинна бути включена в бін. Однак у Visual studio є проблема, що іноді вона не включає посилається dll у папку bin ... це вирішення, яке працювало для мене:

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


1
Повідомлення копіювання було вимкнено, це допомогло 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 Manager Visual Studio не перераховуєтьсяMicrosoft.Extensions.Logging.Console встановлених Project1, незважаючи на його наявність у Project1.csprojфайлі.

Просте вимкнення та перезапуск Visual Studio вирішило проблему без необхідності додавати додаткові посилання. Можливо, це врятує когось 45 хвилин втраченої продуктивності :-)


Насправді я перезапустив весь ПК на своєму тестуванні речей, але це працювало для мене
Noman_1

0

Ви можете встановити і основний проект, і вихідний шлях збірки ProjectX до однієї папки, тоді ви зможете отримати всі необхідні клітини у цій папці.


0

Переконайтесь, що використовуваний вами залежний dll не має цільової .net-рамки вище, ніж цільова .net-рамка програми додатка вашого проекту.

Ви можете перевірити це, вибравши проект, потім натисніть клавішу ALT + ENTER, потім виберіть Застосування з лівого боку та виберіть Цільовий каркас свого проекту.

Припустимо, залежно від dll Target Framework = 4.0 та dll Target Framework = 3.5, а потім змініть це на 4.0

Дякую!


0

Окрім звичайних вище, я мав публікувати багатопроектне рішення. Мабуть, деякі файли націлені на різні рамки.

Тож моє рішення: Властивості> Конкретна версія (помилково)


0

Додайте DLL як існуючий елемент до одного з проектів, і він повинен бути відсортований


0

VS2019 V16.6.3

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

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

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

Якщо ви переходите до посилання на проблемний проект у папці посилань основного проекту, клацніть по ньому та перегляньте властивості, там є налаштування "Копіювати локальне". Приватний тег прирівнюється до цього налаштування, але для мене чомусь зміна локальної копії не вплинула на приватний тег у файлі .proj.

Прикро, що я не змінив місцеве значення копії для посилання, не маю уявлення, як воно встановилося таким чином, і інший день даремно простежував дурну проблему з VS.

Дякую всім іншим відповідям, які допомогли зонувати мене у справі.

HTH

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.