我正在创建一个依赖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)
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?
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: 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.*
.
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:
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.
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.*
.
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.
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
可能无法正常工作。您的项目使用的软件包的版本越旧或越多,该软件包的最旧版本与您的项目一起使用的可能性就越小。
同样,语义版本控制指定次要版本表示不间断的更改,但确实包含新的API。您的项目被打包到使用4.1.x
依赖项的程序包中,NuGet无法知道1)该程序包是否严格符合语义版本控制(我的猜测是非常少)和2)如果您的项目使用的是API仅在4.1.x
而不可用4.0.x
。鉴于并非所有软件包都严格遵守语义版本控制,因此即使更改4.1.*
为也不安全4.1.0
。
希望我已经说服您,NuGet的行为是将项目打包到程序包中时如何处理通配符的行为是最好的方法。它旨在最大限度地提高“开箱即用”的软件包的百分比。如果没有,您现在应该了解它是如何工作的,即使您不同意这是最好的实现。
如果我理解正确,那么您是在说a)PackageReference是设置浮动版本的唯一方法,b)PackageReference是向软件包提供依赖项信息的方式,并且c)软件包不支持浮动版本。我看得对吗?如果是这样,这是否意味着浮动版本不起作用(直到软件包支持它们)?
a)和c)是正确的,但b)不正确。包装他们的.NET项目的包装作者不必担心,NuGet会自动进行。在幕后
<dependencies>
,依赖项在元素的nuspec中指定。我的答案的第二部分试图解释为什么软件包不应该支持浮动版本:(浮动版本可以正常工作,但是它们对于应用程序(GUI,Web,控制台应用程序),未打包到nupkgs中的项目很有用。对于类库不太有用。我已经调整了项目,一切正常,谢谢!我将您的答案标记为接受,但是如果您在解释之前进行了编辑以明确声明解决方案,则对其他人会有所帮助:“将库项目的PackageReference更改为Xamarin.Forms版本4.0.0(实际上是4.0.0.425677)。” 再次感谢!