Подтвердить что ты не робот

Ссылки из библиотеки классов не копируются в папку исполняемого файла проекта bin

У меня есть библиотека классов, представляющая мой логический уровень. В эту библиотеку я добавил пакет nuget для Google.Apis.Analytics.v3 - он установил пакет и все его зависимости.

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

Проблема заключается в том, что во время выполнения он исключил, что Google.Apis.dll не был найден. Эта DLL - это зависимость, которая была загружена с помощью nuget.

Проверяя папки BIN, я обнаружил, что в папке bin библиотеки библиотеки библиотеки эта DLL присутствует, но в папке BIN для консольного приложения она не была (в то время как другие связанные DLL файлы были). Таким образом, это означает, что не все ссылки, скопированные во время компиляции.

Я искал в Интернете и нашел все способы обхода, которые на самом деле не работали (например, вручную редактирование файла проекта и удаление истинной строки xml в этом определении dll).

То, что я закончил, - это добавить ту же библиотеку nuget к моему консольному приложению - она ​​работает, но чувствует себя немного грязной, а не так, как должно быть. Я думаю, что консольное приложение - это клиент, который должен получить эти услуги от этой библиотеки логических классов, которые должны знать это без "клиента", беспокоясь об этом.

Кроме того, это консольное приложение не единственное, кто будет использовать эту услугу, я также планирую веб-приложение, которое будет использовать эту функциональность, поэтому мне нужно будет добавить тот же nuget к этому веб-приложению, снова, чувствует себя немного грязно...

Это только я? что это правильный путь? Я думал о написании проекта WCF, чтобы справиться с этой функциональностью, но это, по-видимому, немного накладные расходы только на функциональность, и, вероятно, замедляет мой рабочий процесс только для того, чтобы держать вещи "чище", на мой взгляд.

Я просто переосмыслил это?

Спасибо

4b9b3361

Ответ 1

Описание

Для примера сценария предположим, что у нас есть проект 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

Если у вас есть следующая цепочка зависимостей: Lib1 < - Lib2 < - MyApp

Версия TL;DR: не делая предположений, система сборки избегает введения неопределенности/непредвиденного поведения.

Когда вы создаете MyApp, Lib2 будет скопирован в каталог bin MyApp для вас, но Lib1 не будет. Вам нужно будет добавить ссылку на Lib2 и Lib1 в MyApp, чтобы получить DLL Lib1 в каталоге bin MyApp (в противном случае вы получите ошибку времени выполнения). Было бы невозможно (или, может быть, просто очень сложно) определить точный набор файлов, которые попадают в каталог Lib2 bin, который был бы безопасным и подходящим для копирования в MyApp. Если система сборки сделала предположения о том, что все в каталоге Lib2 bin безопасно для MyApp или если оно неявно ссылается на Lib1 для вас, это может непреднамеренно изменить поведение MyApp.

Представьте решение, в котором более 1 проекта зависит от Lib2, но один из этих проектов хочет загрузить соседний DLL файл, используя Assembly.LoadFrom/Activator.CreateInstance/MEF/etc. (плагин), а другой нет. Автоматическая операция копирования может захватить Lib2 вместе с плагиной dll и скопировать ее в первый и второй каталог сборки проекта (так как это в каталоге Lib2 bin в результате операции сборки). Это изменит поведение второго приложения.

В качестве альтернативы, если бы вы были немного более умны и неявно ссылались на Lib1 для вас, когда вы ссылались на Lib2 (и не только копировали содержимое каталога bin), это все равно могло бы привести к непредвиденным последствиям. Что, если MyApp уже зависел от Lib1, но он использовал копию GAC'd/ngen'd, которая была совместима с той, которую требует Lib2. Если добавление ссылки на Lib2 неявно создало ссылку на Lib1 для вас, это может изменить загрузку Lib1 и изменить поведение среды выполнения вашего приложения. Возможно, он обнаружил, что в каталоге bin MyApp уже есть Lib1 и пропустить его, но тогда он будет делать предположения, что Lib1, который уже существует, является правильным. Может быть, это устаревшая .dll, ожидающая, чтобы ее уничтожила операция "Чистота", и переписывание было правильным шагом.

NuGet решает проблему, которую вы описываете, с помощью зависимостей пакетов. Если у Lib1 и Lib2 были пакеты nuget, а пакет Lib2 зависел от пакета Lib1, когда вы добавляете Lib2 в MyApp, Lib1 также будет добавлен. Обе библиотеки pacakges в конечном итоге попадут в каталог MyApp bin.

Лучшее, что нужно сделать, это немного перевернуть свое мышление. Вместо того, чтобы думать:

  • Lib2 нуждается в ссылке на Lib1 для компиляции, поэтому я добавлю ссылку на Lib1

Подумайте:

  • MyApp нуждается в Lib2. Что бы ни требовалось Lib2, мне нужно. Таким образом, MyApp и Lib2 получают ссылку на Lib1.