英文:
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
<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>
Then add PrivateAssets="all"
to all ProjectReference
's you want to be packed into parent's package.
Here's how the recommendation works step-by-step:
-
Create or update
./Directory.Build.targets
file:
In the root directory of your project or solution, create or update theDirectory.Build.targets
file. This file allows you to customize the build process across all projects in your solution. -
Define a custom build target:
Within the./Directory.Build.targets
file, define a custom build target namedIncludeP2POutput
. This target will be executed during the build process and will determine which project references to include in the parent project's NuGet package. -
Modify the
TargetsForTfmSpecificBuildOutput
property:
TheTargetsForTfmSpecificBuildOutput
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 addingIncludeP2POutput
to this property, you're telling the build system to run the custom build target for each target framework of the parent project. -
Add
PrivateAssets="all"
to relevantProjectReference
elements:
In your parent project (the one that references other projects), locate theProjectReference
elements that you want to include in the NuGet package. Add the attributePrivateAssets="all"
to theseProjectReference
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. -
Custom build target logic:
The custom build targetIncludeP2POutput
is triggered during the build process and runs after theResolveReferences
target (a built-in target). Inside the target, anItemGroup
is defined to select the project references with the specified metadata values (ReferenceSourceTarget
set to'ProjectReference'
andPrivateAssets
set to'all'
). These references are then added to theBuildOutputInPackage
item group.
By following these steps, when you run dotnet pack
on the parent project, the selected project references with PrivateAssets="all"
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论