分发带有浮动版本的NuGet软件包的正确方法

时间:2019-07-03 15:13:53

标签: xamarin.forms nuget nuget-package

我正在创建一个依赖Xamarin.Forms的NuGet包。该软件包应能与任何最新版本的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 article on package dependency resolution。我还尝试搜索错误消息和“浮动版本”,但我只是在消费者方面找到了解决方法。我想将其修复在我的包装上,以使消费者不必跳圈。

非常感谢任何帮助…

1 个答案:

答案 0 :(得分:0)

项目和软件包之间存在误解。可以使用一个项目创建一个程序包,但是它们具有不同的功能。特别是,浮动版本仅是PackageReference的功能,这是项目定义其程序包依赖性的方式。 The docs say

  

使用PackageReference格式时,NuGet还支持对数字的主要,次要,补丁和预发行后缀部分使用通配符表示法*。 packages.config格式不支持通配符。

对于nuspec也不支持通配符(程序包包含nuspec,而不是PackageReferences),也没有明确说明,但是不支持,因此为什么您的程序包具有>= 4.1.0.555618的依赖关系。然后,正如Matt在评论中指出的那样,由于最近的获胜规则,您将收到降级警告(NuGet将降级视为警告,但.NET Core SDK将其降级为错误。我不知道Xamarin是否做得好与否)。如果您希望您的软件包支持>= 4.0.0,则需要将MyCompany.FormsExtras的{​​{1}}项目的PackageReference更改为Xamarin.Forms版本(尽管您应该使用版本的最低可用版本,否则,使用包的每个项目在找不到与包的依赖项完全匹配时都会对性能产生影响),而不是4.0.0

通配符实施后很长一段时间,我加入了NuGet团队,并且我没有尽力去寻找设计规范,所以我完全猜测,但是我相信打包使用{{1 }}并未导致该软件包支持4.*,因为NuGet会尽最大努力猜测支持的软件包版本,以最大程度地减少使用该软件包的开发人员的运行时故障。

要了解,请考虑最极端的情况,使用通配符4.*。除非NuGet将以某种方式对您的依赖关系的每个版本进行测试,以检查其实际与哪个版本的软件包兼容(完全不可行,即使这样做会使打包非常慢),最简单的两个可以选择使用>= 4.0.0,因为它在精神上等同于*,或者使用上次还原项目时已解决的依赖项版本。

使用>= 0.0.0是一个问题,因为如果软件包的第一个版本与当前版本相比可能有重大更改,或者您的项目可能使用的是最早版本中不提供的API。因此,尽管您的项目使用*,但实际上它与该依赖项的所有版本都不兼容,因此>= 0.0.0可能无法正常工作。您的项目使用的软件包的版本越旧或越多,则该软件包的最旧版本与您的项目一起使用的可能性就越小。

类似地,语义版本控制指定次要版本表示不间断的更改,但确实包含新的API。打包到项目中的项目使用了*的依赖关系,NuGet无法知道1)该项目是否严格符合语义版本控制(我的猜测是很少)和2)如果您的项目项目仅使用>= 0.0.0而非4.1.x中可用的API。鉴于并非所有软件包都严格遵守语义版本控制,因此即使将4.1.x更改为4.0.x也并不安全。

希望我已经使您相信,NuGet在将项目打包到程序包中时如何处理通配符的行为是最好的方法。它旨在最大限度地提高“开箱即用”的软件包的百分比。如果不是这样,即使您不同意这是最好的实现,现在也应该了解它的工作原理。