【问题标题】:How should I publish my projects as NuGet packages considering dependencies between them?考虑到它们之间的依赖关系,我应该如何将我的项目发布为 NuGet 包?
【发布时间】:2022-01-08 13:43:53
【问题描述】:

问题:

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

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

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

假设我有一个根包A。 B、C 和 D 取决于 A。假设E 依赖于B。

假设依赖树如下所示:

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

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

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

请注意项目参考和包参考的区别!

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

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

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

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

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

然后我测试了另一种方法 - 在 Debug 和 Release 配置之间变化的 2 种参考。 Debug 配置引用了项目,Release 配置引用了包。这实际上是很容易管理的,但是,项目文件很乱,都很复杂,维护起来也很繁琐。

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

有人可以确认或否认吗?

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

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

【问题讨论】:

    标签: c# .net nuget nuget-package


    【解决方案1】:

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

    打包项目时,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,然后您可以以任何您喜欢的方式检查这些 nupkg(Visual Studio 的包管理器 UI、NuGet 包资源管理器,只需在文本编辑器中打开 nuspec 文件)并看到 MyLib1 依赖于 MyLib2 版本 1.0.0。在打包时,NuGet 会查看项目引用,确定打包后 MyLib2 的包版本,然后将其用作 MyLib1 中的依赖版本。

    基本上,在您拥有的类库只不过是一个程序集(一堆被编译的.cs 文件)的简单情况下,您真的不需要考虑 NuGet,它只是最简单的工作就像你期望的那样。

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

    有一种方法可以找出并发布包。但它并不是完全可逆的。用于 NuGet 的内容将永远留在那里。

    只有 nuget.org,但没有理由必须为您的包使用 nuget.org。事实上,创建专有软件的公司不可能将其内部包发布到 nuget.org。但是 NuGet 允许您配置多个源,如果您愿意,甚至可以删除 nuget.org。有dotnet nuget add source ... 或dotnet nuget remove source ... 之类的命令。您也可以使用dotnet new nugetconfig 引导一个新的 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.org/downloads 下载 nuget.exe,要么只需手动编辑 nuget.exe 以将文件夹设置到其他位置,这样就不会影响当您dotnet nuget locals global-packages --clear 在您的包测试解决方案中时,您的正常开发。

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

    【讨论】:

      猜你喜欢
      • 2016-08-20
      • 2021-04-02
      • 2011-03-01
      • 2019-03-19
      • 2017-09-24
      • 1970-01-01
      • 1970-01-01
      • 2019-12-20
      • 1970-01-01
      相关资源
      最近更新 更多