考虑到它们之间的依赖关系,我应该如何将我的项目发布为 NuGet 包?

How should I publish my projects as NuGet packages considering dependencies between them?

问题:

我有一个由许多包组成的工具包,源只是一个包含包源、单元测试和演示的大解决方案。

每个包项目都需要是一个单独的 NuGet 包,但有些项目依赖于其他项目。

在项目中,我有本地 项目 依赖项,指向项目文件。

假设我有一个根包 ABCD 取决于 A。假设 E 取决于 B.

假设依赖关系树如下所示:

- A
  |-B-E
  |-C
  |-D

当我发布包时会发生什么 A, B, C, D, E?

E 是否只是项目 E 编译时依赖于 packages B(其中 B 取决于package A) - 或者包 E 没有依赖关系并且 AB projects 内置?

请注意项目参考包参考

之间的区别

在我的解决方案中,我只有项目引用。我在生成的包中想要的是包引用。我的 B.csproj 应该依赖于 A.csproj 但我的 B.nupkg 应该依赖于 A.nupkg.

我想要实现的是能够在不破坏其余包的情况下升级单个包。当然,我指的是非破坏性更改,例如向 A 添加 class 或方法,在不更改 API.

的情况下修复 A 中的错误

假设我在包 A 中发现了一个影响所有其他包的错误。我只想修复包 A 并将其发布为新版本。然后,使用包 B 的项目 X 也应该得到修复,因为它会使用最新版本的 A 依赖项。

是否有可能实现这种行为?我应该怎么做?

我测试了几种(有点)有效的方法。首先,我只是先发布依赖项,然后将 NuGet 包依赖项添加到使用它们的项目中。我指的是后来作为包发布的项目。那行得通,但是调试起来非常乏味。实际上是一场噩梦。

然后我测试了另一种方法 - 2 种引用在 DebugRelease 配置之间变化。 Debug 配置引用了项目,Release 配置引用了包。这实际上是非常易于管理的,但是,项目文件非常混乱,非常复杂并且维护起来仍然很乏味。

我在某处读到过,.NET 和 NuGet 会以某种方式自行解决它。我很难相信。有那么聪明吗?只留下正常的配置,对项目的引用,如果可用,包将引用相应的包?

有人可以证实或否认吗?

有一种方法可以找到并发布包。但这并不是完全可逆的。进入 NuGet 的内容将永远保留在那里。我可以取消列出那些版本,但仍然需要很多时间来测试它,而且会造成混乱。

也许有人已经对此进行了测试,或者找到了一些关于它的可靠信息。

I've read somewhere, that the .NET and NuGet will somehow solve it itself. I find it hard to believe. Is it THAT smart? Just leave normal configuration, references to the projects, and the packages will reference the corresponding packages if available?

打包项目时,NuGet 会将 ProjectReferences 转换为包依赖项,就像 PackageReferences 成为包依赖项一样。没有什么聪明的,事实上它非常简单。因此,无需根据调试与发布或其他任何内容进行切换。验证自己非常容易:

dotnet new sln
dotnet new classlib -n MyLib1
dotnet sln add MyLib1
dotnet new classlib -n MyLib2
dotnet sln add MyLib2
dotnet add MyLib1\MyLib1.csproj reference MyLib2\MyLib2.csproj
dotnet pack

命令行上的这些命令将创建 MyLib1.1.0.0.nupkg 和 MyLib2.1.0.0.nupkg,然后您可以按照自己喜欢的方式检查这些 nupkgs (Visual Studio的 Package Manager UI, NuGet Package Explorer, 只需在文本编辑器中打开 nuspec 文件),看到 MyLib1 对 MyLib2 版本 1.0.0 有依赖。在打包时,NuGet 查看项目引用,确定打包后 MyLib2 的包版本,然后将其用作 MyLib1 中的依赖版本。

基本上,在您拥有 class 个库的简单情况下,这些库只不过是一个程序集(一堆 .cs 已编译的文件),您真的不需要考虑NuGet,它只是以您期望的最简单的方式工作。

由于打包创建的项目的解决方案都是使用ProjectReferences,因此调试或开发并不繁琐,因为NuGet甚至不会发挥作用,直到您完成调试和开发并准备就绪发布。

There's a way to find out, publish the packages. But it's not exactly fully reversible. What goes to NuGet stays there forever.

只有 nuget.org,但您没有理由必须为您的包裹使用 nuget.org。事实上,创建专有软件的公司不可能将其内部包发布到 nuget.org。但是 NuGet 允许您配置多个源,如果您愿意,甚至可以删除 nuget.org。有像 dotnet nuget add source ...dotnet nuget remove source ... 这样的命令。您也可以使用 dotnet new nugetconfig 到 bootstrap 一个新的 nuget.config 文件,然后使用任何文本编辑器直接编辑 xml。语法相当简单,并且都记录在 docs.microsoft.com/nuget.

无论如何,以我之前的例子为例,在创建 MyLib1 和 MyLib2 包后,将它们复制到计算机上的某个文件夹中 Get-ChildItem -recurse -filter *.nupkg | ForEach-Object { Copy-Item $_ c:\path\to\nupkgFolder }。然后创建一个要测试包的新解决方案

dotnet new sln
dotnet new nugetconfig
dotnet nuget add source c:\path\to\nupkgFolder -n LocalNupkgs
dotnet new console -n MyApp
cd MyApp
dotnet add package MyLib1

现在,一个问题是 NuGet 假设所有包 id-version 都是全局唯一且不可变的。这意味着如果你尝试测试你的包,发现错误,修复错误,然后尝试在不更改包版本的情况下进行测试,NuGet 将在你的全局包文件夹中看到该包并使用旧副本,所以你不会看到你的修复。这就是为什么最好不要使用 PackageReference 进行测试,而只使用 ProjectReference。但是无论如何,如果您遇到这种情况,请自己从全局包文件夹中删除包,或者您可以使用 dotnet nuget locals global-packages --clear,这将清除所有包,而不仅仅是您正在测试的包。一直以来对定向删除的需求不大

另一种选择是在测试解决方案的 nuget.config 中设置 globalPackagesFolder 设置。不幸的是 nuget.exe config 还没有移植到 dotnet CLI,所以要么从 nuget 下载 nuget.exe。org/downloads,或者手动编辑 nuget.exe 以将文件夹设置为其他文件夹位置,所以当你在你的包测试解决方案中dotnet nuget locals global-packages --clear时,它不会影响你的正常开发。

This docs page 还列出了多个用于托管您自己的私人提要的选项,尽管本地文件夹最容易进行调试。许多公司使用网络文件共享而不是服务器,但请注意,由于 nuget 无法索引本地文件夹或网络共享上的包元数据,因此使用 Visual Studio 的包管理器 UI 会比托管 HTTP 提要(确实有搜索索引),如果文件夹包含许多 nupkgs 时恢复速度也较慢,我不会感到惊讶。