在一个解决方案中声明相互依赖的 nuget 包

declaring nuget packages that depend on each other in one solution

我们有很多项目的解决方案以及这些项目之间或多或少复杂的依赖关系图。现在,这些项目中的每一个都应该成为自己的 nuget 包,并且 nuget 包的依赖关系图应该反映项目的依赖关系图。

我有两个问题:

  1. 是否可以在将所有项目保持在同一个解决方案中的同时实现这一点?如果有怎么办?
  2. 建议将所有项目保持在同一个解决方案中吗?常见的/"best practice" 方法是什么?

是的,您可以"probably"完成这项工作。我说这可能是因为我还没有尝试过,但我会用这样的方法来处理它:https://www.nuget.org/packages/CreateNewNuGetPackageFromProjectAfterEachBuild/ 使用手动 nuspec 定义您的引用会起作用。如果你想变得非常花哨,你可以编写一些 post-build Roslyn 代码来解析你的项目依赖项并构建 nuget 依赖项树。也就是说,不要这样做,在一个不平凡的解决方案中,它几乎可以保证很快变得手动和脆弱。

最终,最好只是分解您的解决方案——为每个 Nuget 包创建一个解决方案,并使用 Nuget 本身引入您的依赖项。假设您有一个 build/CI 服务器,这应该是微不足道的。只需 运行 你自己的 Nuget 存储库并在构建时发布构建工件——这样你的依赖项目就会拉取你刚刚构建的最新包。您需要确保您的构建过程每次都刷新 Nuget,并且您可以使用标准 nuget spec 命令作为 post-构建步骤。作为一个不错的奖励,它会迫使所有从事代码工作的人在进行更改时真正考虑依赖关系。

我们项目中的情况是一样的,我们采取了以下做法:

第一步是创建定义包的 nuspec 文件。我们已将所有这些文件放在名为“.nuspec”的文件夹中,该文件夹位于解决方案的根目录中。 nuspec 文件也添加到名为“.nuspec”的解决方案文件夹中的解决方案。

解决方案本身有一个全局 AssemblyInfo 文件,其中包含版本控制信息以及一些版权信息 - 简而言之,我们项目之间的所有信息都是通用的。然后每个项目都有自己的程序集信息,添加特定于每个项目的信息。

nuspec 文件不包含版本。相反,我们使用 $(version) 作为占位符:

<?xml version="1.0" encoding="utf-16"?>
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
  <metadata>
    <id>MyCompany.MyProduct.Server.DataAccess</id>
    <version>$(Version)</version>
    <authors>MyCompany</authors>
    <projectUrl>http://example.com/myProduct.html</projectUrl>
    <iconUrl>http://example.com/myProduct.icon.png</iconUrl>
    <requireLicenseAcceptance>false</requireLicenseAcceptance>
    <description>Some description goes here.</description>
    <summary>The summary goes here</summary>
    <copyright>Copyright © MyCompany 2015</copyright>
    <language>en-US</language>
    <dependencies>
      <dependency id="MyCompany.MyProduct.Common" version="$(Version)" />
      <dependency id="MyCompany.MyProduct.Server" version="$(Version)" />
    </dependencies>
  </metadata>
  <files>
    <file src="path\to\MyCompany.MyProduct.Server.DataAccess.dll" target="lib\net45\MyCompany.MyProduct.Server.DataAccess.dll" />
  </files>
</package>

(当然,依赖项本身可能有依赖项。例如,服务器组件可能会引用日志记录组件。)

最初我们创建了一个控制台应用程序,从全局 AssemblyInfo 文件中读取解决方案的版本,并在创建和发布程序包之前将其解析为所有 nuspec 文件。

控制台应用程序运行良好,但在启用持续集成的 TFS 环境中维护起来有点乏味。所以我们定义了一个自定义 TFS 构建模板来完成这项工作。我们现在需要做的就是为我们所有的项目创建一组 nuget 包,就是触发 TFS 构建。

这种方法的优点是所有包都具有相同的版本,因此可以很好地协同工作。 这种方式的缺点是所有包都是同一个版本,不能独立发布。

我们之所以选择这种方法,是因为它可以防止我们产生大量集成不良的组件。我们的项目提供了一个小型框架,用于开发非常相似的小型 LOB 应用程序。由于我们在一组不同的包中交付框架,开发人员可以选择他们实际需要的包,然后只安装那些包。如果开发人员决定稍后添加缺少的功能,他只需安装与已安装的版本相同的相关包。因此无需担心兼容性问题。

目前,在 VS 2017 中,您可以在一个解决方案中拥有多个库项目,这些项目被构建到单独的包中,并且还通过 <ProjectReference> 相互引用。令人惊讶的是,VS 足够聪明,可以在构建解决方案时使用 <ProjectReference> 并为 nuspec 中的引用项目生成正确的包 <dependencies>。换句话说,您可以方便地在一个解决方案中同时处理多个项目,并将它们全部发布为一组相互依赖的包。