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

时间:2022-03-27 13:00:06

We have solution with a lot of projects and a more or less complex dependency graph between those projects. Now each of those projects should become its own nuget package and the dependency graph of the nuget packages should mirror the on of the projects.

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

I have two questions:

我有两个问题:

  1. Is it possible to achieve this while keeping all projects within the same solution? If so how?
  2. 是否有可能在保持所有项目在同一解决方案中的同时实现这一目标?如果是这样的话?
  3. Is advisable to keep all projects in the same solution? What would be the a common / "best practice" approach to this?
  4. 建议将所有项目保持在同一解决方案中吗?对此有什么共同/“最佳实践”方法?

3 个解决方案

#1


6  

The situation in our project is the same and we took the following approach:

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

The first step is to create the nuspec files defining your packages. We have placed all theses files in a folder named ".nuspec" which is located in the solution's root directory. The nuspec files are added to the solution in a solution folder that is named ".nuspec", too.

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

The solution itself has a global AssemblyInfo file that contains the versioning information as well as some copyright stuff - in short all information that is common between our projects. Each project then has its own assembly info adding the information specific to each project.

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

The nuspec files do not contain a version. Instead we use $(version) as a placeholder there:

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>

(Of course the dependencies might have dependencies themselves. The server component might reference a logging component for example.)

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

Initially we created a console application reading the version of the solution from the global AssemblyInfo file and parsing it into all of the nuspec files before creating and publishing the packages.

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

The console application worked well, but was a bit tedious to maintain in a TFS environment with continuous integration enabled. So we defined a custom TFS build template doing this work. All we need to do now to create a set of nuget packages for all of our projects is to trigger a TFS build.

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

This approach has the advantage that all packages have the same version and thus work well together. This approach has the disadvantage that all packages have the same version and cannot be released independently.

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

We chose that approach because it prevented us from producing a conglomerate of badly integrated components. Our projects provide a small framework that is used to develop small LOB-applications that all are quite similar. Due to the fact that we deliver the framework in a set of different packages the developers can choose which of the packages they actually need and then install only those. Should a developer decide to add a missing functionality lateron he just installs the relevant packages that have the same version as those already installed. Thus there's no need to worry about compatibility.

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

#2


2  

Yes, you can "probably" make this work. I say probably because I haven't tried it, but I would approach it with something like this: https://www.nuget.org/packages/CreateNewNuGetPackageFromProjectAfterEachBuild/ with a manual nuspec defining your references would work. If you wanted to get really fancy, you could write some post-build Roslyn code to parse your project dependencies and build up the nuget dependency tree. That said, don't do this, in a non-trivial solution, its almost guaranteed to become manual and brittle pretty fast.

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

Ultimately, it's much preferable to just break your solution up -- create a solution per Nuget package, and pull in your dependencies using Nuget itself. Assuming you have a build/CI server, this should be fairly trivial. Just run your own Nuget repo and publish the build artifacts as they get built -- that way your dependent projects will pull the latest package you JUST built. You'll want to ensure your build process refreshes Nuget each time and you can use the standard nuget spec command as a post-build step. As a nice bonus, it'll force everyone working on the code to really think thru the dependencies when making changes.

最终,最好只是破解你的解决方案 - 为每个Nuget包创建一个解决方案,并使用Nuget本身提取你的依赖关系。假设您有一个构建/ CI服务器,这应该是相当简单的。只需运行你自己的Nuget repo并在构建时发布构建工件 - 这样你的依赖项目就会获取你刚刚构建的最新包。您需要确保每次构建过程都刷新Nuget,并且可以使用标准nuget spec命令作为构建后步骤。作为一个很好的奖励,它会强制每个处理代码的人在进行更改时真正考虑依赖关系。

#3


2  

Currently, in VS 2017 you can have several library projects in a solution which are built into separate packages and also reference each other by <ProjectReference>. Surprisingly, VS is smart enough to use <ProjectReference> when building solution AND to produce correct package <dependencies> for referenced projects in nuspec. In other words, you can conveniently work with many projects simultaneously in one solution and have them all published as a set of packages depending on each other.

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

#1


6  

The situation in our project is the same and we took the following approach:

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

The first step is to create the nuspec files defining your packages. We have placed all theses files in a folder named ".nuspec" which is located in the solution's root directory. The nuspec files are added to the solution in a solution folder that is named ".nuspec", too.

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

The solution itself has a global AssemblyInfo file that contains the versioning information as well as some copyright stuff - in short all information that is common between our projects. Each project then has its own assembly info adding the information specific to each project.

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

The nuspec files do not contain a version. Instead we use $(version) as a placeholder there:

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>

(Of course the dependencies might have dependencies themselves. The server component might reference a logging component for example.)

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

Initially we created a console application reading the version of the solution from the global AssemblyInfo file and parsing it into all of the nuspec files before creating and publishing the packages.

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

The console application worked well, but was a bit tedious to maintain in a TFS environment with continuous integration enabled. So we defined a custom TFS build template doing this work. All we need to do now to create a set of nuget packages for all of our projects is to trigger a TFS build.

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

This approach has the advantage that all packages have the same version and thus work well together. This approach has the disadvantage that all packages have the same version and cannot be released independently.

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

We chose that approach because it prevented us from producing a conglomerate of badly integrated components. Our projects provide a small framework that is used to develop small LOB-applications that all are quite similar. Due to the fact that we deliver the framework in a set of different packages the developers can choose which of the packages they actually need and then install only those. Should a developer decide to add a missing functionality lateron he just installs the relevant packages that have the same version as those already installed. Thus there's no need to worry about compatibility.

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

#2


2  

Yes, you can "probably" make this work. I say probably because I haven't tried it, but I would approach it with something like this: https://www.nuget.org/packages/CreateNewNuGetPackageFromProjectAfterEachBuild/ with a manual nuspec defining your references would work. If you wanted to get really fancy, you could write some post-build Roslyn code to parse your project dependencies and build up the nuget dependency tree. That said, don't do this, in a non-trivial solution, its almost guaranteed to become manual and brittle pretty fast.

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

Ultimately, it's much preferable to just break your solution up -- create a solution per Nuget package, and pull in your dependencies using Nuget itself. Assuming you have a build/CI server, this should be fairly trivial. Just run your own Nuget repo and publish the build artifacts as they get built -- that way your dependent projects will pull the latest package you JUST built. You'll want to ensure your build process refreshes Nuget each time and you can use the standard nuget spec command as a post-build step. As a nice bonus, it'll force everyone working on the code to really think thru the dependencies when making changes.

最终,最好只是破解你的解决方案 - 为每个Nuget包创建一个解决方案,并使用Nuget本身提取你的依赖关系。假设您有一个构建/ CI服务器,这应该是相当简单的。只需运行你自己的Nuget repo并在构建时发布构建工件 - 这样你的依赖项目就会获取你刚刚构建的最新包。您需要确保每次构建过程都刷新Nuget,并且可以使用标准nuget spec命令作为构建后步骤。作为一个很好的奖励,它会强制每个处理代码的人在进行更改时真正考虑依赖关系。

#3


2  

Currently, in VS 2017 you can have several library projects in a solution which are built into separate packages and also reference each other by <ProjectReference>. Surprisingly, VS is smart enough to use <ProjectReference> when building solution AND to produce correct package <dependencies> for referenced projects in nuspec. In other words, you can conveniently work with many projects simultaneously in one solution and have them all published as a set of packages depending on each other.

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