使用浮动版本分发 NuGet 包的正确方法

sta*_*kos 4 nuget nuget-package xamarin.forms

我正在创建一个依赖于 Xamarin.Forms 的 NuGet 包。该包应该可以与任何最新版本的 Forms 一起正常工作,因此我将其设置为:

\n\n
<Project Sdk="Microsoft.NET.Sdk">\n\n  <PropertyGroup>\n    <TargetFramework>netstandard2.0</TargetFramework>\n    <PackageId>MyCompany.FormsExtras</PackageId>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include="Xamarin.Forms" Version="4.*" />\n  </ItemGroup>\n</Project>\n
Run Code Online (Sandbox Code Playgroud)\n\n

在本地构建并发布以测试...

\n\n
$ dotnet pack -c Release -p:Version=0.9.0\n$ nuget add bin/Release/MyCompany.FormsExtras.0.9.0.nupkg -source ~/Dropbox/Packages/\n
Run Code Online (Sandbox Code Playgroud)\n\n

当我运行这些命令时,Xamarin.Forms 4.1.0.555618 是最新版本。

\n\n

我现在尝试将此包放入现有项目中,该项目直接依赖于不同的旧版本的 Xamarin.Forms:

\n\n
$ dotnet pack -c Release -p:Version=0.9.0\n$ nuget add bin/Release/MyCompany.FormsExtras.0.9.0.nupkg -source ~/Dropbox/Packages/\n
Run Code Online (Sandbox Code Playgroud)\n\n

...但它无法添加包并出现以下错误:

\n\n
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. \n MyCompany.ToDo.Forms -> MyCompany.FormsExtras 0.9.0 -> Xamarin.Forms (>= 4.1.0.555618) \n MyCompany.ToDo.Forms -> Xamarin.Forms (>= 4.0.0.425677)\n
Run Code Online (Sandbox Code Playgroud)\n\n

我的印象是我的包中指定的浮动版本PackageReference应该允许它工作?我是否错过了一个步骤,或者我只是误解了浮动版本的工作原理?

\n\n

我已经阅读了MS 关于包依赖性解析的文章。我还尝试搜索错误消息和“浮动版本”,但我只在消费者端找到解决方法;我想在我的包装上解决这个问题,这样消费者就不必费劲了。

\n\n

非常感谢任何帮助\xe2\x80\xa6

\n

ziv*_*kan 9

TL;DR 版本:将 PackageReference 更改为使用Version=4.0.0,或最低版本的项目使用的相同版本,而不是Version=4.*.

项目和包之间存在误解。项目可以用来创建包,但它们具有不同的功能。特别是,浮动版本只是 的一个功能PackageReference,这是项目定义其包依赖项的方式。文档说

使用 PackageReference 格式时,NuGet 还支持对数字的 Major、Minor、Patch 和预发布后缀部分使用通配符 * 表示。packages.config 格式不支持通配符。

它也没有明确说明 nuspec 不支持通配符(包包含 nuspec,而不是PackageReferences),但它不受支持,因此为什么您的包具有>= 4.1.0.555618. 然后,正如 Matt 在评论中指出的那样,由于最近的胜利规则,您会收到降级警告(NuGet 将降级视为警告,但 .NET Core SDK 将其提升为错误。我不知道 Xamarin 是否也可以或不可以)。如果您希望您的包支持>= 4.0.0,那么您需要将MyCompany.FormsExtras项目的PackageReferencefor更改Xamarin.Forms为 版本4.0.0(尽管您应该使用可用的最低版本的确切版本,否则每个使用您的包的项目在找不到时都会受到性能影响与您的包的依赖项完全匹配),而不是4.*.

4.*在通配符实现后很长一段时间我加入了 NuGet 团队,并且我没有努力寻找设计规范,所以我完全猜测,但我相信打包使用的项目不会导致包的原因支持>= 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 处理通配符的行为是最好的方法。它旨在最大限度地提高“开箱即用”的软件包的百分比。如果没有,您现在应该了解它是如何工作的,即使您不同意它是最好的实现。

  • “对于类库来说不太有用。” - 他们实际上清楚地记录了这一点,这很有用,它给我带来了真正的混乱,需要我清理。说实话,nuget 文档确实不好。 (2认同)