使用浮动版本分发 NuGet 包的正确方法 [英] Correct way to distribute NuGet package with floating version

查看:30
本文介绍了使用浮动版本分发 NuGet 包的正确方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在创建一个依赖于 Xamarin.Forms 的 NuGet 包.该包应该适用于任何最新版本的 Forms,因此我将其设置为:

I'm creating a NuGet package that depends on Xamarin.Forms. The package should work fine with any recent version of Forms, so I set it up like:

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

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

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

在本地构建和发布以进行测试...

Build and publish locally to test...

$ 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 是最新版本.

At the time I ran these commands, Xamarin.Forms 4.1.0.555618 was the latest version.

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

I'm now trying to pull this package into an existing project which has a direct dependency on a different, older version of Xamarin.Forms:

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

...但它无法添加此错误的包:

...but it fails to add the package with this error:

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 中指定的浮动版本应该允许它工作?我是否遗漏了一步,或者我只是误解了浮动版本的工作原理?

I was under the impression that the floating version specified in my package's PackageReference should have allowed this to work? Am I missing a step, or do I just misunderstand how floating versions work?

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

I've read through the MS article on package dependency resolution. I also tried searching on the error message and "floating version" but I'm only finding workarounds on the consumer side; I'd like to fix this on my packaging so the consumers don't have to jump through hoops.

非常感谢任何帮助......

Any help much appreciated…

推荐答案

TL;DR version: 更改您的 PackageReference 以使用 Version=4.0.0,或项目使用的与最低版本,而不是 Version=4.*.

TL;DR version: Change your PackageReference to use Version=4.0.0, or the same version used by the project with the lowest version, instead of Version=4.*.

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

There's a misunderstanding between a project and a package. A project can be used to create a package, but they have different features. In particular, floating versions are a features only of PackageReference, which is how a project defines its package dependencies. The docs say:

在使用 PackageReference 格式时,NuGet 还支持使用通配符 * 表示数字的主要、次要、补丁和预发布后缀部分.package.config 格式不支持通配符.

When using the PackageReference format, NuGet also supports using a wildcard notation, *, for Major, Minor, Patch, and pre-release suffix parts of the number. Wildcards are not supported with the packages.config format.

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

It's not explicit about the nuspec not supporting wildcards either (a package contains a nuspec, not PackageReferences), but it isn't supported hence why your package has a dependency of >= 4.1.0.555618. Then as Matt pointed out in the comments, you're getting the downgrade warning because of the nearest wins rule (and NuGet treats the downgrade as a warning, but the .NET Core SDK elevates it to an error. I have no idea if Xamarin does as well or not). If you want your package to support >= 4.0.0, then you need to change the MyCompany.FormsExtras project's PackageReference for Xamarin.Forms to version 4.0.0 (although you should use the exact version of the lowest version available, otherwise every project that uses your package will have a performance hit when it can't find an exact match of your package's dependency), not 4.*.

我在通配符实现后很长一段时间加入了 NuGet 团队,我没有努力寻找设计规范,所以我完全是猜测,但我相信打包使用 的项目的原因4.* 不会导致包支持 >= 4.0.0 是因为 NuGet 正在尽最大努力猜测支持哪些包版本,以尽量减少使用包.

I joined the NuGet team a long time after wildcards were implemented, and I made no effort of trying to find a design spec, so I'm totally guessing, but I believe the reason why packing a project that uses 4.* does not result in the package supporting >= 4.0.0 is because NuGet is making a best effort guess about what package versions are supported to minimise runtime failures for developers using the package.

要理解,请考虑最极端的情况,使用通配符 *.除非 NuGet 会以某种方式使用依赖项的每个版本测试您的项目,以检查它实际上与哪些版本的包兼容(这样做完全不可行,即使这样也会使打包速度非常慢),最简单的两个选项是使用 >= 0.0.0 因为它在精神上等同于 *,或者使用上次恢复项目时解决的依赖项版本.

To understand, consider the most extreme case, using a wildcard of *. Unless NuGet is going to somehow test your project with every version of your dependency to check which versions of the package it's actually compatible with (totally infeasible to do so, and even if it were it would making packing so very slow), the easiest two options are to either use >= 0.0.0 as that's spiritually equivalent to *, or use the version of the dependency that was resolved the last time the project was restored.

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

Using >= 0.0.0 is a problem because if the the very first version of a package might have breaking changes compared to the current version, or your project might be using APIs that are not available in earliest versions. Therefore, despite your project using *, it's not actually compatible with all versions of that dependency, so >= 0.0.0 might not work. The older, or the more versions, the package your project uses has, the less likely that the oldest versions of that package will work with your project.

同样,语义版本控制指定次要版本表示非破坏性更改,但确实包含新的 API.打包到包中的项目使用了依赖项的 4.1.x,而 NuGet 无法知道 1) 包是否严格符合语义版本控制(我的猜测是非常非常少)2) 如果您的项目使用的 API 仅适用于 4.1.x 而不是 4.0.x.鉴于并非所有包都严格遵守语义版本控制,甚至将 4.1.* 更改为 4.1.0 也是不安全的.

Similarly, Semantic Versioning specifies that the minor version signifies non-breaking changes, but does contain new APIs. Your project that was packed into a package used 4.1.x of your dependency, and NuGet has no way of knowing if 1) the package strictly conforms to semantic versioning (my guess is very, very few do) and 2) if your project is using an API only available in 4.1.x and not 4.0.x. Given not all packages strictly conform to semantic versioning, it's unsafe to even change 4.1.* to 4.1.0.

希望我已经让您确信 NuGet 在将项目打包到包中时如何处理通配符的行为是最好的方法.它旨在最大化开箱即用"的包的百分比.如果不是,您现在应该了解它是如何工作的,即使您不同意这是最好的实现.

Hopefully I've convinced you that NuGet's behaviour of how wildcards are handled when the project is packed into a package is the best approach. It's designed to maximise the percentage of packages that work "out of the box". If not, you should now understand how it works even if you don't agree it's the best implementation.

这篇关于使用浮动版本分发 NuGet 包的正确方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆