Pull to refresh

Comments 22

А теперь расскажите, пожалуйста, как вы, собственно, решаете следующие проблемы:

  1. Необходимость копировать из проекта в проект исходники/бинарники — неудобно, долго, велика вероятность ошибки при обновлении.
  2. Невозможность использования разных версий для разных проектов — поиск и сборка конкретной версии «из прошлого» неудобны, опять же велика вероятность ошибки при обновлении.
  3. Необходимость следить за актуальностью зависимостей библиотеки — особенно это касается Azure SDK, который сейчас регулярно обновляется, не всегда у всех разработчиков стоит последняя версия, и обновление SDK не всегда возможно.
  4. Использование существующего проекта на разных машинах — ещё одно «тонкое» место, порождающее много ненужных ошибок. Для корректной работы необходимо полное совпадение путей для проектов, чего очень сложно добиться.



А то я весь пост вижу только разговор про то, как автоматически опубликовать nuget-package.

Особенно мне интересно, конечно, как вы решаете проблему «библиотека хочет одну версию зависимостей, проект хочет другую версию зависимостей».
1. Подключаем пакет через NuGet-менеджер — обращаемся к своему NuGet-репозиторию, получаем последнюю версию проекта во время сборки.
2. Через NuGet-менеджер можно запросить конкретную версию пакета, и производить сборку именно через него.
3. В пакет закладывается не только наша библиотека, но и все её зависимости (те же азуровские библиотеки).
4. Библиотеки при получении через NuGet во время сборки корректно находятся компилятором.

Собственно, после подключения к своему NuGet-фиду проблемы были решены (по крайней мере, у нас).

Пожалуйста, уточните ваш последний вопрос — я его не очень понял.
Подключаем пакет через NuGet-менеджер — обращаемся к своему NuGet-репозиторию, получаем последнюю версию проекта во время сборки.

Вот прямо из коробки? Без каких-либо дополнительных настроек, особенно на TFS?

Через NuGet-менеджер можно запросить конкретную версию пакета, и производить сборку именно через него.

… а что будет, если разные проекты в солюшне используют разные версии пакета?

В пакет закладывается не только наша библиотека, но и все её зависимости (те же азуровские библиотеки).

А что будет, если разные версии пакета смотрят на разные версии зависимостей?

Библиотеки при получении через NuGet во время сборки корректно находятся компилятором.

Ну вообще нет. Компилятор про nuget ничего не знает.

Пожалуйста, уточните ваш последний вопрос — я его не очень понял.

Очень просто.

У вас есть ваш собственный проект, он смотрит на, скажем, Entity Framework 4. У вас есть подключенный nuget-package, который смотрит на Entity Framework 5. Что получится?
Вот прямо из коробки? Без каких-либо дополнительных настроек, особенно на TFS?

Не очень понятно, при чём тут TFS — или вы имеете ввиду VS на машине разработчика?
Там, конечно, должен стоять расширение NuGet, для корректной работы с пакетами.

… а что будет, если разные проекты в солюшне используют разные версии пакета?

Так как в разных проектах прописаны разные NuGet-targets, проекты и получат разные пакеты (у нас сейчас в solution есть около 10 версий, всё корректно собирается).

А что будет, если разные версии пакета смотрят на разные версии зависимостей?

Всё зависит от того, на какой пакет настроен ваш проект, и включено ли у вас обновление пакетов при сборке — если да, то при обновлении библиотек могут возникнуть ошибки сборки, да.

Ну вообще нет. Компилятор про nuget ничего не знает.

Согласен, неверно сформулировал. Я имел ввиду, что при сборке проекта NuGet-расширение исследует файл *.targets на предмет всех нужных пакетов, и если какие-то не получены, и включена их подгрузка — оно их загружает/обновляет, после чего сборка проекта идёт дальше.

У вас есть ваш собственный проект, он смотрит на, скажем, Entity Framework 4. У вас есть подключенный nuget-package, который смотрит на Entity Framework 5. Что получится?


Для решения таких случаев можно, например, в PowerShell скрипт добавить код прописывания bindingRedirect, например:
<dependentAssembly>
    <assemblyIdentity name="EntityFramework" publicKeyToken="b77a5c561934e089" culture="neutral" />
    <bindingRedirect oldVersion="0.0.0.0-5.0.0.0" newVersion="5.0.0.0" />
</dependentAssembly>

Данный код из web.config взят с реального проекта. Такой bindingRedirect прописывается пакетами Azure SDK. Разумеется, данный подход так же может породить ошибки компиляции, так как в новой EntityFramework может не быть какого-то либо функционала из прошлых версий.

Что будет без подобного редиректа — не проверял, но, видимо, будет следующее:
Код проекта, пытающийся вызвать функционал из пакета, завязанный на Entity Framework, породит ошибку компиляции.
Не очень понятно, при чём тут TFS — или вы имеете ввиду VS на машине разработчика?

При том, что проекты собираются не только локально.

Так как в разных проектах прописаны разные NuGet-targets, проекты и получат разные пакеты (у нас сейчас в solution есть около 10 версий, всё корректно собирается).

И не попадают в общий bin при результирующей сборке?

Я имел ввиду, что при сборке проекта NuGet-расширение исследует файл *.targets на предмет всех нужных пакетов, и если какие-то не получены, и включена их подгрузка — оно их загружает/обновляет, после чего сборка проекта идёт дальше.

… и это тоже не из коробки.

Разумеется, данный подход так же может породить ошибки компиляции, так как в новой EntityFramework может не быть какого-то либо функционала из прошлых версий.

Именно. Нарушение обратной совместимости в полный рост.

Код проекта, пытающийся вызвать функционал из пакета, завязанный на Entity Framework, породит ошибку компиляции.

Именно.

Что, в общем-то, означает, что nuget-пакеты не решают проблемы реальной работы с разными версиями одной зависимости. Проверено на практике.
Прошу прощения, вклинюсь.

Я обычно для этих целей использую субрепозитории в Mercurial или Git.
Каждая подключаемая библиотека вервионируется в своем репо, который подключается к проекту- потребителю.
Смена версии библиотеки, при этом, это отдельный коммит с тестированием.
Конечно, для TFS это не применимо.
Вот как раз и было интересно решение автора…
Но все равно, спасибо за статью.
Что не применимо?
Субрепозитории. У меня чего-то комменты самоотравляются…
В TFS такие вещи спокойно делаются через отдельные папки и бранчи. В чем проблема-то?
Пожалуйста.
В документации к NuGetter есть пример создания пакета из двух решений с разными версиями .NET Framework.
Там библиотеки рассовываются в разные папки в одном пакете.

Соответственно, можно запаковать и старую, и новую версии.
Вы, похоже, вообще не понимаете, о чем говорите.

Разные версии .net framework в nuget-пакете — это разные референсы для проектов с разной целевой версией .net. При этом если у вас будет два таких (разных) проекта в одном солюшне и они, не дай б-г, будут потом пореференсены из одного проекта — у вас будет все тот же самый цирк с невозможностью разобрать зависимости.
А насколько часто лично вам приходилось встречаться с тем, что в рамках одного solution встречались проекты, работающие с разными версиями одной и той же библиотеки?
За последнюю неделю — трижды. И это, что характерно, был нюгетовский пакет.
Надо признаться, вы меня сильно задели, указав на неполное решение задачи.
Долго думал, обращался к первоисточникам, и хотел бы доформулировать свою мысль насчёт разных папок для библиотек пакета.

1. Согласно известной книге Рихтера, глава 2, для каждой сборки в конфигурационном файле приложения можно указать относительный PrivatePath, где CLR будет искать файлы, относящиеся к данной сборке:
<configuration>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <probing privatePath="AuxFiles" />
    </assemblyBinding>
  </runtime>
</configuration>


2. Прописать данную настройку в .config файле можно с помощью PowerShell скрипта, идущего вместе с package.

3. При сборке пакета можно запаковать библиотеки именно в указанную Private Path.

Соответственно, во время сборки солюшена с разными версиями пакета зависимости будут храниться в отдельных папках, и друг друга не перетрут.

Единственная пока проблема — не смог найти поддержку работы с Private Path в документации NuGet. Спросил в их блоге, посмотрим, что ответят. Если будет работать, обновлю статью.
Согласно известной книге Рихтера, глава 2, для каждой сборки в конфигурационном файле приложения можно указать относительный PrivatePath, где CLR будет искать файлы, относящиеся к данной сборке:

Нельзя. Это общий путь приложения, а не каждой сборки. Это даже из примера видно — там сама сборка нигде не указывается.
Да, не всё так радужно, как показалось.
Согласно MSDN, в параметр Private Path можно указывать не одну папку, а несколько.
Правда, не уверен, что всё это будет корректно собираться, буду пробовать.
Согласно MSDN, в параметр Private Path можно указывать не одну папку, а несколько.

Можно. Будет искаться в нескольких папках. Найдется все равно конкретная версия, а дальше будут конфликты.
При том, что проекты собираются не только локально.

Я не настраивал билды проектов, кроме «общей» библиотеки, так что опыт не очень большой — но никаких особых действий для включения поддержки NuGet на TFS-сервере не производилось.
Библиотека собралась со всеми пакетными зависимостями.

И не попадают в общий bin при результирующей сборке?

Здесь наврал, извините. В рамках одного solution — одна версия пакета.

… и это тоже не из коробки.

Да, подразумевается, что на машине разработчика стоит NuGet-расширение — работа с Azure намекает на необходимость данного условия.

Именно. Нарушение обратной совместимости в полный рост.

Да, выбор сделан не в пользу поддержки старых версий — по примеру Azure SDK.

Что, в общем-то, означает, что nuget-пакеты не решают проблемы реальной работы с разными версиями одной зависимости. Проверено на практике.

Спасибо за пищу для размышлений. У нас ситуация пока проще, чем вы описали.
Может быть, есть что-либо почитать на эту тему?
Я не настраивал билды проектов, кроме «общей» библиотеки, так что опыт не очень большой

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

Здесь наврал, извините. В рамках одного solution — одна версия пакета.

А это значит, что вы не решали проблему работы с разными версиями.

Да, подразумевается, что на машине разработчика стоит NuGet-расширение — работа с Azure намекает на необходимость данного условия.

Я снова про TFS, если что.

Спасибо за пищу для размышлений. У нас ситуация пока проще, чем вы описали.

… но при этом в начале статьи-то вы замахиваетесь на больше, чем у вас сейчас есть. О чем я и говорил.

Может быть, есть что-либо почитать на эту тему?

Если бы было, я бы вам дал ссылку сразу.
В следующий раз буду более аккуратен в выражениях, спасибо.
Sign up to leave a comment.

Articles