Правильный способ распространения пакета NuGet с плавающей версией - PullRequest
0 голосов
/ 03 июля 2019

Я создаю пакет NuGet, который зависит от Xamarin.Forms. Пакет должен нормально работать с любой последней версией Forms, поэтому я настроил его так:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>
    <PackageId>MyCompany.FormsExtras</PackageId>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Xamarin.Forms" Version="4.*" />
  </ItemGroup>
</Project>

Создание и публикация локально для проверки ...

$ dotnet pack -c Release -p:Version=0.9.0
$ nuget add bin/Release/MyCompany.FormsExtras.0.9.0.nupkg -source ~/Dropbox/Packages/

В то время, когда я запускал эти команды, Xamarin.Forms 4.1.0.555618 была последней версией.

Я сейчас пытаюсь перетащить этот пакет в существующий проект, который напрямую зависит от другой, более старой версии Xamarin.Forms:

  <ItemGroup>
    <PackageReference Include="Xamarin.Forms" Version="4.0.0.425677" />
  </ItemGroup>

... но не удается добавить пакет с этой ошибкой:

Detected package downgrade: Xamarin.Forms from 4.1.0.555618 to 4.0.0.425677. Reference the package directly from the project to select a different version. 
 MyCompany.ToDo.Forms -> MyCompany.FormsExtras 0.9.0 -> Xamarin.Forms (>= 4.1.0.555618) 
 MyCompany.ToDo.Forms -> Xamarin.Forms (>= 4.0.0.425677)

У меня сложилось впечатление, что плавающая версия, указанная в PackageReference моего пакета, должна была позволить этому работать? Я пропускаю шаг, или я просто неправильно понимаю, как работают плавающие версии?

Я прочитал статью MS по разрешению зависимостей пакетов . Я также попытался найти сообщение об ошибке и «плавающую версию», но я нахожу обходные пути только на стороне потребителя; Я бы хотел исправить это на своей упаковке, чтобы потребители не прыгали через обручи.

Любая помощь высоко ценится

1 Ответ

0 голосов
/ 04 июля 2019

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

При использовании формата PackageReference NuGet также поддерживает использование подстановочных знаков * для основных, второстепенных, исправлений и суффиксов перед выпуском части номера. Подстановочные знаки не поддерживаются в формате packages.config.

Не ясно, что nuspec не поддерживает подстановочные знаки (пакет содержит nuspec, а не PackageReferences), но это не поддерживается, поэтому ваш пакет имеет зависимость >= 4.1.0.555618. Затем, как указал Мэтт в комментариях, вы получаете предупреждение о понижении рейтинга из-за правила ближайших побед (и NuGet рассматривает понижение рейтинга как предупреждение, но .NET Core SDK выводит его на ошибку. Я понятия не имею, если Xamarin так же хорошо или нет). Если вы хотите, чтобы ваш пакет поддерживал >= 4.0.0, вам нужно изменить MyCompany.FormsExtras проекта *1013* для Xamarin.Forms на версию 4.0.0 (хотя вы должны использовать точную версию самой низкой доступной версии, в противном случае каждый проект который использует ваш пакет, будет иметь снижение производительности, когда не сможет найти точное соответствие зависимости вашего пакета), а не 4.*.

Я присоединился к команде NuGet спустя долгое время после внедрения подстановочных знаков, и я не пытался найти спецификацию проекта, так что я полностью догадываюсь, но я верю в причину, по которой стоит упаковывать проект, использующий 4.* не приводит к тому, что пакет, поддерживающий >= 4.0.0, объясняется тем, что NuGet делает все возможное, чтобы угадать, какие версии пакетов поддерживаются, чтобы минимизировать сбои времени выполнения для разработчиков, использующих пакет.

Чтобы понять, рассмотрим самый крайний случай, используя подстановочный знак *. Если только NuGet не собирается каким-либо образом тестировать ваш проект с каждой версией вашей зависимости, чтобы проверить, с какими версиями пакета он фактически совместим (это абсолютно невозможно, и даже если бы это делало упаковку такой очень медленной), самые простые два можно либо использовать >= 0.0.0, поскольку это духовно эквивалентно *, либо использовать версию зависимости, которая была разрешена при последнем восстановлении проекта.

Использование >= 0.0.0 является проблемой, потому что, если в самой первой версии пакета могут быть критические изменения по сравнению с текущей версией, или ваш проект может использовать API, которые недоступны в самых ранних версиях. Поэтому, несмотря на то, что ваш проект использует *, он на самом деле не совместим со всеми версиями этой зависимости, поэтому >= 0.0.0 может не работать. Чем старше или больше версий используется пакет вашего проекта, тем меньше вероятность того, что самые старые версии этого пакета будут работать с вашим проектом.

Аналогично, семантическое управление версиями указывает, что младшая версия означает неразрывные изменения, но содержит новые API. Ваш проект, который был упакован в пакет, использовал 4.1.x вашей зависимости, и NuGet не может знать, если 1) пакет строго соответствует семантическому версионированию (я думаю, что очень, очень немногие делают) и 2) если ваш проект использование API доступно только в 4.1.x и не 4.0.x. Поскольку не все пакеты строго соответствуют семантическому версионированию, небезопасно даже изменять 4.1.* на 4.1.0.

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

...