如何将一个被引用的项目打包成一个NuGet包?

huangapple go评论60阅读模式
英文:

How to pack a referenced project into a nuget package?

问题

我有一个包含3个项目的C#解决方案;Application.Server、Application.Client和Application.Common。服务器和客户端都引用了Common项目。

我想打包服务器和客户端,以便其他团队在我的组织中可以使用它们。我已经设置了一些自动化构建流水线来执行此操作,并发布了服务器和客户端的NuGet包。它们不会打包或发布Common项目。当我检查NuGet包时,我可以看到它们引用了Common包。

有没有办法让它们将Common项目构建到自身中?理想情况下,我不想发布Common包,因为它与我的应用程序非常相关,而且它并不是其他部门可以独立使用的东西。我也不想担心额外的NuGet包,如果可能的话(因为实际上,Common实际上是由多个项目组成的)。

英文:

I have a C# solution which contains 3 projects; Application.Server, Application.Client, and Application.Common. Both server and client have a project reference to common.

I want to pack server and client up so that they can be used by other teams in my organisation. I have some automated build pipeline set up that do so, and they publish the nuget packages for server and client. They do not package or publish common. When I inspect the nuget packages, I can see that they reference the common package.

Is there a way that I can get them to build that project into them self? Ideally I don't want to publish the common package as it's pretty specific to my application, and it doesn't really make sense that it's something that's independently consumable by other departments. I also don't want to have to worry about wrangling extra nuget packages if I can help it (as in reality, Common is actually several projects).

答案1

得分: 14

如果您的项目采用“旧式”/非SDK/传统csproj方式,并且如果任何项目使用了NuGet包,如果所有这些NuGet引用都是使用packages.config定义的,那么您可以使用nuget.exe pack -IncludeReferencedProjects。但是,如果您的任何项目使用PackageReference来定义其包引用(新的SDK样式项目只能使用PackageReference),那么nuget.exe pack将无法正确地为这些包创建NuGet依赖项。对于SDK样式的多目标项目,nuget pack可能会完全失败。

对于使用PackageReference的项目或任何SDK样式项目,唯一受支持的打包方式是使用NuGet的MSBuild打包目标(要么dotnet pack要么msbuild -t:pack)。然而,这没有等同于nuget.exe的IncludeReferencedProjects

如果您的项目是SDK样式的,创建和发布一个或多个包实际上不应该更加困难。只需在解决方案上运行dotnet pack,每个可打包的项目都会被打包(请记住标记任何您不希望成为包的类库项目为不可打包)。然后使用您喜欢的脚本语言查找并发布所有nupkg文件。例如(Get-ChildItem -Recurse -Filter *.nupkg $SLN_DIR | ForEach-Object { & dotnet nuget push $_ }),或将所有nupkg复制/移动到一个地方(或使用适当的设置使NuGet首次在那里创建包),然后使用dotnet nuget push *.nupkg

NuGet团队建议每个程序集一个包,并且工具会自动为项目引用创建NuGet依赖项,因此一切都可以“一切正常”。要创建一个包,其中包含所有程序集,而不是NuGet依赖项,需要您进行大量的工作。

英文:

If your projects are "old style"/non-SDK/traditional csproj, AND if any project uses a NuGet package, if all those NuGet references are defined using packages.config, then use you can use nuget.exe pack -IncludeReferencedProjects. However, if any of your projects use PackageReference to define their package references (new, SDK-style projects can only use PackageReference), then nuget.exe pack will not correctly create NuGet dependencies for those packages. For SDK style multi-targeting projects, nuget pack will probably completely fail.

The only supported way to pack projects that use PackageReference, or any SDK style project, is to use NuGet's MSBuild pack target (either dotnet pack or msbuild -t:pack). However, this does not have an equivalent to nuget.exe's IncludeReferencedProjects.

If your projects are SDK style, it really shouldn't be any more difficult to create and publish one package or many packages. Simply run dotnet pack on your solution, and every packable project gets packed (remember to mark any class library project you don't want to become a package as not packable). Then use your favourite scripting language to find and publish all nupkg files. For example (Get-ChildItem -Recurse -Filter *.nupkg $SLN_DIR | ForEach-Object { & dotnet nuget push $_ }, or copy/move all nupkgs to a single place (or use the appropriate setting to make NuGet create the packages there in the first place) and use dotnet nuget push *.nupkg.

The NuGet team recommends one package per assembly, and the tooling automatically creates NuGet dependencies for project references, so it all "just works" out of the box. To create a package with all the assemblies included, instead of NuGet dependencies, requires you to do a bunch of work.

答案2

得分: -3

将以下内容放入./Directory.Build.targets中:

<Project>
  <PropertyGroup>
    <TargetsForTfmSpecificBuildOutput>$(TargetsForTfmSpecificBuildOutput);IncludeP2POutput</TargetsForTfmSpecificBuildOutput>
  </PropertyGroup>

  <Target Name="IncludeP2POutput" DependsOnTargets="ResolveReferences">
    <ItemGroup>
      <BuildOutputInPackage Include="@(ReferenceCopyLocalPaths->WithMetadataValue('ReferenceSourceTarget', 'ProjectReference')->WithMetadataValue('PrivateAssets', 'all'))" />
    </ItemGroup>
  </Target>
</Project>

然后将PrivateAssets="all"添加到所有要打包到父级包中的ProjectReference中。

英文:

Put the following into ./Directory.Build.targets

&lt;Project&gt;
  &lt;PropertyGroup&gt;
    &lt;TargetsForTfmSpecificBuildOutput&gt;$(TargetsForTfmSpecificBuildOutput);IncludeP2POutput&lt;/TargetsForTfmSpecificBuildOutput&gt;
  &lt;/PropertyGroup&gt;

  &lt;Target Name=&quot;IncludeP2POutput&quot; DependsOnTargets=&quot;ResolveReferences&quot;&gt;
    &lt;ItemGroup&gt;
      &lt;BuildOutputInPackage Include=&quot;@(ReferenceCopyLocalPaths-&gt;WithMetadataValue(&#39;ReferenceSourceTarget&#39;, &#39;ProjectReference&#39;)-&gt;WithMetadataValue(&#39;PrivateAssets&#39;, &#39;all&#39;))&quot; /&gt;
    &lt;/ItemGroup&gt;
  &lt;/Target&gt;
&lt;/Project&gt;

Then add PrivateAssets=&quot;all&quot; to all ProjectReference's you want to be packed into parent's package.

Here's how the recommendation works step-by-step:

  1. Create or update ./Directory.Build.targets file:
    In the root directory of your project or solution, create or update the Directory.Build.targets file. This file allows you to customize the build process across all projects in your solution.

  2. Define a custom build target:
    Within the ./Directory.Build.targets file, define a custom build target named IncludeP2POutput. This target will be executed during the build process and will determine which project references to include in the parent project's NuGet package.

  3. Modify the TargetsForTfmSpecificBuildOutput property:
    The TargetsForTfmSpecificBuildOutput property is used by the .NET build system to determine which targets should be executed during the build process for a specific target framework. By adding IncludeP2POutput to this property, you're telling the build system to run the custom build target for each target framework of the parent project.

  4. Add PrivateAssets=&quot;all&quot; to relevant ProjectReference elements:
    In your parent project (the one that references other projects), locate the ProjectReference elements that you want to include in the NuGet package. Add the attribute PrivateAssets=&quot;all&quot; to these ProjectReference elements. This attribute tells the build system to treat these references as private assets, meaning they won't be treated as dependencies by the consuming projects.

  5. Custom build target logic:
    The custom build target IncludeP2POutput is triggered during the build process and runs after the ResolveReferences target (a built-in target). Inside the target, an ItemGroup is defined to select the project references with the specified metadata values (ReferenceSourceTarget set to &#39;ProjectReference&#39; and PrivateAssets set to &#39;all&#39;). These references are then added to the BuildOutputInPackage item group.

By following these steps, when you run dotnet pack on the parent project, the selected project references with PrivateAssets=&quot;all&quot; will be included in the NuGet package of the parent project. Other projects consuming the parent project as a package will not see these references as dependencies, making them effectively hidden.

Please note that the behavior and capabilities of the .NET SDK and build system may evolve over time, so it's essential to refer to the official Microsoft documentation and release notes for the most up-to-date information on this topic.

huangapple
  • 本文由 发表于 2020年1月6日 19:43:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/59611527.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定