我有一个 C# 解决方案,其中包含 3 个项目;应用程序服务器、应用程序客户端和应用程序公共端。服务器和客户端都有一个对 common 的项目引用。
我想打包服务器和客户端,以便我组织中的其他团队可以使用它们。我设置了一些自动构建管道来执行此操作,并且他们为服务器和客户端发布 nuget 包。他们不打包或发布通用的。当我检查 nuget 包时,我可以看到它们引用了 common 包。
有没有办法让他们自己构建该项目?理想情况下,我不想发布通用包,因为它非常特定于我的应用程序,并且它是其他部门独立使用的东西并没有真正意义。如果我能帮忙的话,我也不想担心额外的 nuget 包(事实上,Common 实际上是几个项目)。
如果您的项目是“旧式”/非 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 依赖项的包,需要您做大量工作。
将以下内容放入
./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
。
以下是建议的逐步运作方式:
创建或更新
./Directory.Build.targets
文件:
在项目或解决方案的根目录中,创建或更新 Directory.Build.targets
文件。该文件允许您自定义解决方案中所有项目的构建过程。
定义自定义构建目标: 在
./Directory.Build.targets
文件中,定义一个名为 IncludeP2POutput
的自定义构建目标。该目标将在构建过程中执行,并将确定要包含在父项目的 NuGet 包中的项目引用。
修改
TargetsForTfmSpecificBuildOutput
属性:
.NET 构建系统使用 TargetsForTfmSpecificBuildOutput
属性来确定在特定目标框架的构建过程中应执行哪些目标。通过向此属性添加 IncludeP2POutput
,您可以告诉构建系统为父项目的每个目标框架运行自定义构建目标。
将
PrivateAssets="all"
添加到相关 ProjectReference
元素:
在父项目(引用其他项目的项目)中,找到要包含在 NuGet 包中的 ProjectReference
元素。将属性 PrivateAssets="all"
添加到这些 ProjectReference
元素。此属性告诉构建系统将这些引用视为私有资产,这意味着它们不会被使用项目视为依赖项。
自定义构建目标逻辑: 自定义构建目标
IncludeP2POutput
在构建过程中触发,并在 ResolveReferences
目标(内置目标)之后运行。在目标内部,定义 ItemGroup
来选择具有指定元数据值的项目引用(ReferenceSourceTarget
设置为 'ProjectReference'
和 PrivateAssets
设置为 'all'
)。然后,这些引用将添加到 BuildOutputInPackage
项目组中。
按照以下步骤操作,当您在父项目上运行
dotnet pack
时,带有 PrivateAssets="all"
的所选项目引用将包含在父项目的 NuGet 包中。将父项目作为包使用的其他项目不会将这些引用视为依赖项,从而使它们有效地隐藏。
请注意,.NET SDK 和构建系统的行为和功能可能会随着时间的推移而发展,因此有必要参考 Microsoft 官方文档和发行说明,以获取有关此主题的最新信息。