Управление обновлениями зависимостей в проекте .NET

Завершено

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

Прежде чем приступать к обновлению библиотеки, примите во внимание несколько моментов.

  • Тип обновления: какой тип обновления доступен? Является ли обновление небольшим исправлением? Добавит ли оно нужную вам возможность? Нарушает ли код? Тип обновления можно узнать с помощью системы так называемого семантического управления версиями. Способ выражения номера версии библиотеки сообщает разработчикам о типе обновления, с которым они имеют дело.
  • Правильно ли настроен проект: вы можете настроить проект .NET, чтобы получить только нужные типы обновлений. Обновление выполняется только в том случае, если доступен определенный тип обновления. Такой подход рекомендуется, так как он позволяет избежать сюрпризов.
  • Проблемы безопасности. Управление зависимостями проекта с течением времени включает в себя учет проблем, которые могут произойти. Проблемы возникают, например, при обнаружении уязвимостей. В идеале исправления выпускаются, которые можно скачать. Средство .NET Core помогает выполнять аудит библиотек и определять наличие пакетов, требующих обновления. Она также помогает выполнять действия, необходимые для устранения проблемы.

Использование семантического управления версиями

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

  • Основной номер версии — первое число слева. Например, это 1 вход 1.0.0. Изменение этого числа означает, что в коде можно ожидать "критические изменения". Возможно, часть кода придется переписать.
  • Дополнительный номер версии — число посередине. Например, это 2 вход 1.2.0. Изменение этого числа означает, что добавлены функции. Код должен работать, как и раньше. Обычно это безопасно для принятия обновления.
  • номер версии исправления — последнее число. Например, это 3 вход 1.2.3. Изменение этого числа означает, что было применено изменение, которое исправляет что-то в коде, который должен работать. Такое обновление должно быть безопасным.

В приведенной ниже таблице показано, как изменяется номер версии при обновлении каждого типа.

Тип Что происходит
Основной номер версии 1.0.0 изменения в 2.0.0
Дополнительный номер версии 1.1.1 изменения в 1.2.0
Версия исправления 1.0.1 изменения в 1.0.2

Многие компании и разработчики используют эту систему. Если вы планируете публиковать пакеты и отправлять их в реестр NuGet, ожидается, что вы будете следовать семантической версии. Этим правилам должны соответствовать даже те пакеты, которые вы скачиваете из реестра NuGet.

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

Метод обновления

Разработчик .NET может сообщить о поведении обновления, которое требуется .NET. При обновлении в первую очередь следует учитывать риск. Вот несколько подходов:

  • Основной номер версии — обновление до последней основной версии можно установить, как только оно будет выпущено. Я принимаю тот факт, что мне может потребоваться изменить код со своей стороны.
  • Дополнительный номер версии — добавление новой функции меня устраивает. Меня не устраивает только нарушение работы кода.
  • Номер версии исправления — единственное, что устраивает меня, — это исправления ошибок.

Если вы управляете новым или небольшим проектом .NET, то можете себе позволить свободу в выборе стратегии обновления. Например, можно всегда обновляться до последней версии. В более сложных проектах больше дополнительных нюансов, но их мы обсудим в последующих модулях.

Как правило, чем меньше зависимости, чем вы обновляете, тем меньше зависимостей, которые он имеет, и тем более вероятно, что процесс обновления прост.

Настройка файла проекта для обновления

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

Диапазоны версий — это специальная нотация, которую можно использовать для указания определенного диапазона версий, которые требуется разрешить.

Представление Примененное правило Description
1.0 x >= 1,0 Минимальная версия, включающая
(1.0,) x > 1.0 Минимальная версия, исключающая
[1.0] x == 1.0 Точное соответствие версии
(,1.0] x ≤ 1.0 Максимальная версия, включающая
(,1.0) x < 1.0 Максимальная версия, исключающая
[1.0,2.0] 1.0 ≤ x ≤ 2.0 Точный диапазон, включающий
(1.0,2.0) 1.0 < x < 2.0 Точный диапазон, исключающий
[1.0,2.0) 1.0 ≤ x < 2.0 Смешанная включающая минимальная и исключающая максимальная версии
(1.0) недопустимо недопустимо

NuGet также поддерживает использование нотации с плавающей версией для основных, дополнительных, исправлений и предварительных суффиксов номера. Подстановочным знаком является звездочка (*). Например, спецификация версии 6.0.* говорит: "Используйте последнюю версию 6.0.x". В другом примере 4.* означает "использовать последнюю версию 4.x". Использование с плавающей версией уменьшает изменения в файле проекта, сохраняя актуальность последней версии зависимости.

Примечание.

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

При использовании версии с подстановочным знаком NuGet разрешает самую новую версию пакета, соответствующую шаблону версии. В следующем примере указано 6.0.*, а значит, вы получаете последнюю версию пакета, начинающуюся с 6.0. Это версия 6.0.1.

Схема, показывающая выбор последней версии при запросе плавающей версии.

Вот несколько примеров для настройки основной версии, дополнительной версии или версии исправления.

<!-- Accepts any version 6.1 and later. -->
<PackageReference Include="ExamplePackage" Version="6.1" />

<!-- Accepts any 6.x.y version. -->
<PackageReference Include="ExamplePackage" Version="6.*" />
<PackageReference Include="ExamplePackage" Version="[6,7)" />

<!-- Accepts any later version, but not including 4.1.3. Could be
     used to guarantee a dependency with a specific bug fix. -->
<PackageReference Include="ExamplePackage" Version="(4.1.3,)" />

<!-- Accepts any version earlier than 5.x, which might be used to prevent pulling in a later
     version of a dependency that changed its interface. However, we don't recommend this form because determining the earliest version can be difficult. -->
<PackageReference Include="ExamplePackage" Version="(,5.0)" />

<!-- Accepts any 1.x or 2.x version, but not 0.x or 3.x and later. -->
<PackageReference Include="ExamplePackage" Version="[1,3)" />

<!-- Accepts 1.3.2 up to 1.4.x, but not 1.5 and later. -->
<PackageReference Include="ExamplePackage" Version="[1.3.2,1.5)" />

Поиск и обновление устаревших пакетов

Команда dotnet list package --outdated выводит список устаревших пакетов. С ее помощью можно узнать, доступны ли более новые версии пакетов. Вот типичный результат выполнения этой команды:

Top-level Package      Requested   Resolved   Latest
> Humanizer            2.7.*       2.7.9      2.8.26

Столбцы в выходных данных имеют следующее значение:

  • Requested: указанный диапазон версий или версий.
  • Resolved: фактическая версия, скачаемая для проекта, которая соответствует указанной версии.
  • Latest: последняя версия, доступная для обновления из NuGet.

Эти команды рекомендуется выполнять в следующем порядке:

  1. Запустите dotnet list package --outdated. Она выводит список всех устаревших пакетов. Сведения возвращаются в столбцах Requested, Resolved и Latest.
  2. Запустите dotnet add package <package name>. При выполнении этой команды она пытается обновить до последней версии. При необходимости вы можете передать --version=<version number/range>.