Я не уверен, почему это отличается при сборке между Visual Studio и MsBuild, но вот что я обнаружил, когда столкнулся с этой проблемой в MsBuild и Visual Studio.
Объяснение
Для примера сценария предположим, что у нас есть проект X, сборка A и сборка B. Сборка A ссылается на сборку B, поэтому проект X содержит ссылку как на A, так и на B. Кроме того, проект X включает код, который ссылается на сборку A (например, A.SomeFunction ()).Теперь вы создаете новый проект Y, который ссылается на проект X.
Таким образом, цепочка зависимостей выглядит следующим образом: Y => X => A => B
VisualStudio / MSBuild старается быть умным и привносить в проект Y только те ссылки, которые он обнаруживает как необходимые для проекта X;он делает это, чтобы избежать загрязнения ссылок в проекте Y. Проблема в том, что проект X на самом деле не содержит никакого кода, который явно использует сборку B (например, B.SomeFunction ()), VS / MSBuild не обнаруживает, что требуется BX и, следовательно, не копирует его в каталог bin проекта Y;он копирует только сборки X и A.
Решение
У вас есть два варианта решения этой проблемы, каждый из которых приведет к копированию сборки B в каталог bin проекта Y:
- Добавить ссылку на сборку 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'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);
}