NuGet 依赖策略

NuGet Dependency Strategy

我正在将我的许多应用程序模型和接口拆分到它自己的 nuGet 包中。

问题是:在创建 nuGet 包时,是否有关于依赖项定义的良好实践推荐策略?

有时 package A 依赖于 package B。如果我没有在我的 package A 的 nuspec 上声明特定的 package B 版本,当我稍后在任何解决方案中导入 package A nuGet 包时,它可能会在 运行 处失败时间,因为子依赖项不可用。

有时依赖树会变得更深。但是,如果我明确地将依赖项添加到每个 nuspec 文件,那么我以后可能会发现版本冲突。

问题是:如果一切都在我的控制之下,处理这些事情的建议策略是什么?我是否应该仅在项目的依赖项 "not obvious" 时指定依赖项(例如:导入 nuGet 包装器的项目在 运行 时需要但不直接使用的第三方库)?我应该一直这样做,以后再以不同的方式处理版本冲突吗?任何关于此的良好信息来源将不胜感激,因为我找到了几个例子,但没有推荐某种做事方式。

附件: 我创建 nuGet 包的方法是包含一个我手动编辑的 nuspec 文件。例如,如果我有以下解决方案结构:

ToolBelt.CityContracts.sln
-ToolBelt.CityContracts.NuGet
--ToolBelt.CityContracts.NuGet.nuspec
-ToolBelt.CityContractsOne
-ToolBelt.CityContractsTwo

ToolBelt.CityContractsOneToolBelt.CityContractsTwo 中,我有我的 c# 源文件。在 ToolBelt.CityContracts.NuGet 项目中,我添加了对 ToolBelt.CityContractsOneToolBelt.CityContractsTwo 的引用,以确保源文件所在的 nuspec "knows"。

然后 nuspec 看起来像这样:

<?xml version="1.0" encoding="utf-8" ?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
  <metadata>
    <id>ToolBelt.CityContracts</id>
    <version>1.0.0</version>
    <authors>iberodev</authors>
    <requireLicenseAcceptance>false</requireLicenseAcceptance>
    <description>Shared Contracts</description>
    <dependencies>
      <!--here sub-dependencies that I want to drag across-->
    </dependencies>
  </metadata>
  <files>
    <file src="bin/*/netstandard2.0/ToolBelt.CityContractsOne.dll" target="lib/netstandard2.0" />
    <file src="bin/*/netstandard2.0/ToolBelt.CityContractsOne.pdb" target="lib/netstandard2.0" />
    <file src="bin/*/netstandard2.0/ToolBelt.CityContractsTwo.dll" target="lib/netstandard2.0" />
    <file src="bin/*/netstandard2.0/ToolBelt.CityContractsTwo.pdb" target="lib/netstandard2.0" />
  </files>
</package>

到这里为止一切都很标准。

然后我使用 nuget 命令工具在名为 nupkgs 的文件夹中生成 nuget 包,命令如下:

nuget pack ToolBelt.CityContracts.NuGet.nuspec -Version $VERSION -OutputDirectory nupkgs -Prop Configuration=Release -NoDefaultExcludes -Verbosity detailed

更新 1: 现在我的策略如下。

  1. 如果 package A 在属于 package B 的 public API 中公开 classes/interfaces,则 package A 不会在其 nuspec 中添加对 package B 的依赖。因此添加 package A 的项目也必须显式添加 package B
  2. 如果 package A 没有在它的 public API 中暴露 classes/interfaces 是 package B 的一部分,但它在内部使用它们,那么package A 必须在其 nuspec 中添加对 package B 的依赖,以便添加 package A 的项目也会自动安装 package B 并避免 运行time 异常风险。

想法是:如果代码编译,它应该 运行 没有 运行 由于不存在的依赖项而导致的时间异常。

这对我来说很有意义,但我找不到任何可靠的来源来确认这是要走的路。

由于您的目标是 netstandard2.0,创建包的更简单方法是使用 dotnet pack, rather than creating a nuspec yourself and using nuget pack. dotnet pack or msbuild /t:pack will pull metadata from the csproj and it automatically adds any PackageReference as a dependency to your package. if you have a build-time dependency that you don't want users of your package to get, you can use PrivateAssets

最佳做法是将所有运行时依赖项作为依赖项添加到您的包中,这样任何只引用您的包的人,他们的程序都不会因缺少 dll 而在运行时崩溃。当不同的包请求不同的版本时,NuGet 恢复会自动处理依赖项的版本选择,因此您通常不应该花太多时间担心,尽管坚持使用语义版本控制会有所帮助。

附带一提,我个人的观点是包越少越好。接口的实现可能与接口的定义不同 assembly/package 的原因绝对有很多。但是除非你能有充分的理由证明它的合理性,否则我建议将接口和实现保持在相同的 assembly/package。我过去工作的一个代码库在多个存储库的多个包中都有代码,因为团队认为一些通用代码可能对其他项目有用。但是 bug 修复意味着您必须创建一个新版本的依赖项,然后更新已部署应用程序中的引用,并且依赖项的调试很困难。当我们不得不处理那个依赖包时,这会大大减慢开发速度,最后没有其他人使用它,所以拆分它真的没有任何好处。