【问题标题】:NuGet Dependency StrategyNuGet 依赖策略
【发布时间】:2018-10-22 08:47:53
【问题描述】:

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

问题是:在创建nuGet包时,关于依赖关系的定义有什么好的实践推荐策略吗?

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

有时依赖关系树会更深。但是如果我在每个 nuspec 文件中显式添加依赖项,那么我以后可能会发现版本冲突。

问题是:如果一切都在我的控制之下,推荐的处理这些事情的策略是什么?我是否应该仅在依赖项对项目“不明显”时才指定依赖项(例如:导入 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“知道”源文件的位置。

那么 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 在其公共API 中公开属于package B 的类/接口,则package A 不会在其nuspec 中添加对package B 的依赖项。因此添加package A 的项目也必须显式添加package B
  2. 如果package A 没有在其公共API 中公开属于package B 的类/接口,但它在内部使用它们,那么package A 必须在其nuspec 中添加对package B 的依赖关系,所以添加package A的项目也会自动安装package B,避免运行时异常风险。

这个想法是:如果代码编译,它应该在没有运行时异常的情况下运行,因为不存在依赖项。

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

【问题讨论】:

    标签: c# nuget nuget-package nuspec


    【解决方案1】:

    由于您的目标是 netstandard2.0,创建包的更简单方法是使用 dotnet pack,而不是自己创建 nuspec 并使用 nuget packdotnet packmsbuild /t:pack 将从 csproj 中提取元数据,并自动将任何 PackageReference 作为依赖项添加到您的包中。如果您不希望软件包的用户获得构建时依赖项,则可以使用PrivateAssets

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

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

    【讨论】:

    • dotnet pack 很感兴趣,但是使用多个包的解决方案会发生什么情况?我可以看到您只能将一个项目传递给dotnet pack。如果您想打包另一个孤立的项目怎么办?
    • 如果你有一个 sln 文件,它会尝试打包解决方案中的每个项目。您有 MSBuild 属性来防止打包(来自内存 IsPackable),因此如果您真的不希望打包某些项目,您可以避免打包它们。或者,还有一个 MSBuild 属性 GeneratePackageOnBuild,因此 nupkg 将在构建时自动创建。无需单独运行pack。
    • 我在这里阅读了dotnet pack 文档docs.microsoft.com/en-us/dotnet/core/tools/…,似乎唯一允许的参数是要打包的项目。没有指定解决方案的选项。您是否有一个示例/链接,其中使用dotnet pack 打包了多项目解决方案并自定义了 nuGet Id? (我通过自己定义 nuspec 来做到这一点)
    • 使用&lt;PackageId&gt; in your csproj。尝试在 sln 文件上运行 dotnet pack 以查看它是否有效需要几秒钟的时间,即使文档没有声称它可以。我将在文档上创建一个问题,因此希望对其进行更新。或者,您可以设置 `<GeneratePackageOnBuild> property in your csrpoj,并且您不需要将 pack 作为单独的步骤运行。
    猜你喜欢
    • 1970-01-01
    • 2020-03-23
    • 2014-05-07
    • 1970-01-01
    • 2018-08-21
    • 2017-10-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多