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.CityContractsOne
和 ToolBelt.CityContractsTwo
中,我有我的 c# 源文件。在 ToolBelt.CityContracts.NuGet
项目中,我添加了对 ToolBelt.CityContractsOne
和 ToolBelt.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:
现在我的策略如下。
- 如果
package A
在属于 package B
的 public API 中公开 classes/interfaces,则 package A
不会在其 nuspec 中添加对 package B
的依赖。因此添加 package A
的项目也必须显式添加 package B
- 如果
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 修复意味着您必须创建一个新版本的依赖项,然后更新已部署应用程序中的引用,并且依赖项的调试很困难。当我们不得不处理那个依赖包时,这会大大减慢开发速度,最后没有其他人使用它,所以拆分它真的没有任何好处。
我正在将我的许多应用程序模型和接口拆分到它自己的 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.CityContractsOne
和 ToolBelt.CityContractsTwo
中,我有我的 c# 源文件。在 ToolBelt.CityContracts.NuGet
项目中,我添加了对 ToolBelt.CityContractsOne
和 ToolBelt.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: 现在我的策略如下。
- 如果
package A
在属于package B
的 public API 中公开 classes/interfaces,则package A
不会在其 nuspec 中添加对package B
的依赖。因此添加package A
的项目也必须显式添加package B
- 如果
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 修复意味着您必须创建一个新版本的依赖项,然后更新已部署应用程序中的引用,并且依赖项的调试很困难。当我们不得不处理那个依赖包时,这会大大减慢开发速度,最后没有其他人使用它,所以拆分它真的没有任何好处。