名称: dotnet-artifacts-output 描述: “配置构建输出布局。使用 UseArtifactsOutput、ArtifactsPath,以及对 CI 和 Docker 的影响。” 用户可调用: false
dotnet-artifacts-output
.NET SDK 构建输出布局参考指南,用于将构建输出(bin/、obj/、publish/、package/)集中到仓库根目录的单个 artifacts/ 目录中。自 .NET 8 起作为可选功能提供。推荐用于新项目;迁移现有项目前评估利弊。
先决条件: 首先运行 [skill:dotnet-version-detection] 以确认 .NET 8+ SDK – 构建输出布局在早期 SDK 版本中不可用。
范围
- UseArtifactsOutput 可选和 ArtifactsPath 配置
- 集中构建输出布局(artifacts/bin/、artifacts/obj/、artifacts/publish/)
- 对 CI 工件上传路径和 Docker 构建的影响
- 现有项目的迁移利弊
超出范围
- 源代码树组织(.sln、.csproj、src/、tests/) – 见 [skill:dotnet-project-structure]
交叉引用: [skill:dotnet-project-structure] 用于解决方案布局,[skill:dotnet-containers] 用于 Dockerfile 路径调整,[skill:dotnet-gha-build-test] 用于 CI 工件上传路径,[skill:dotnet-scaffold-project] 用于生成启用构建输出的新项目。
为什么使用构建输出布局
传统的 .NET 构建输出将 bin/ 和 obj/ 目录分散在整个源代码树中,每个项目一个。构建输出布局将所有构建输出整合到 Directory.Build.props 旁边的单个 artifacts/ 目录下。
好处:
- 更简单的
.gitignore– 一个artifacts/条目替换每个项目的bin/和obj/条目 - 更容易清理构建 – 删除一个目录,而不是查找分散的
bin//obj/文件夹 - 可预测的输出路径 – 工具可以预测找到构建输出的位置,无需遍历源代码树
- 更干净的源代码树 – 构建工件不会混入项目目录
权衡:
- 破坏路径假设 – 必须更新引用
bin/Debug/net10.0/路径的现有 CI 管道、Dockerfiles 和工具 - IDE/工具兼容性 – 一些较旧工具可能无法正确解析新输出路径
- 迁移努力 – 现有项目需要更新所有硬编码的输出路径引用
启用构建输出布局
在仓库根目录的 Directory.Build.props 中添加 UseArtifactsOutput:
<Project>
<PropertyGroup>
<UseArtifactsOutput>true</UseArtifactsOutput>
</PropertyGroup>
</Project>
或者,生成一个预配置构建输出的新 Directory.Build.props:
dotnet new buildprops --use-artifacts
这将创建:
<Project>
<PropertyGroup>
<ArtifactsPath>$(MSBuildThisFileDirectory)artifacts</ArtifactsPath>
</PropertyGroup>
</Project>
直接设置 ArtifactsPath 等同于 UseArtifactsOutput=true,并且允许您自定义根目录位置。
输出路径结构
所有构建输出按三个级别组织在 artifacts/ 下:输出类型、项目名称和枢轴(配置/TFM/RID)。
artifacts/
bin/
MyApp/
debug/ # 单目标项目
debug_net10.0/ # 多目标项目
release_linux-x64/ # RID 特定构建
MyApp.Core/
debug/
obj/
MyApp/
debug/
publish/
MyApp/
release/ # dotnet publish 输出
release_linux-x64/ # RID 特定发布
package/
release/ # NuGet .nupkg 文件(无项目子文件夹)
输出类型目录
| 目录 | 内容 | 传统等价物 |
|---|---|---|
artifacts/bin/ |
编译的程序集和依赖项 | <project>/bin/ |
artifacts/obj/ |
中间构建文件、生成的代码 | <project>/obj/ |
artifacts/publish/ |
发布的应用程序输出 | <project>/bin/<config>/<tfm>/publish/ |
artifacts/package/ |
NuGet 包(.nupkg、.snupkg) |
<project>/bin/<config>/ |
枢轴命名
枢轴子文件夹组合配置、TFM 和 RID,用下划线连接。不存在的组件被省略:
| 场景 | 枢轴 | 完整路径示例 |
|---|---|---|
| 单目标,调试 | debug |
artifacts/bin/MyApp/debug/ |
| 多目标,调试 | debug_net10.0 |
artifacts/bin/MyApp/debug_net10.0/ |
| 发布,RID 特定 | release_linux-x64 |
artifacts/bin/MyApp/release_linux-x64/ |
| 包输出 | release |
artifacts/package/release/ |
注意:artifacts/package/ 省略项目名称子文件夹。枢轴仅包括配置。
自定义构建输出路径
自定义根目录
设置 ArtifactsPath 以更改根位置:
<PropertyGroup>
<ArtifactsPath>$(MSBuildThisFileDirectory).output</ArtifactsPath>
</PropertyGroup>
这将所有构建输出放在 .output/ 下,而不是 artifacts/。
自定义枢轴
使用 ArtifactsPivots 自定义枢轴子文件夹命名:
<PropertyGroup>
<ArtifactsPivots>$(ArtifactsPivots)_MyCustomPivot</ArtifactsPivots>
</PropertyGroup>
对 .gitignore 的影响
启用构建输出布局后,简化 .gitignore:
# 构建输出布局(替换每个项目的 bin/ 和 obj/ 条目)
artifacts/
这个单一条目替换传统模式:
# 传统布局(构建输出布局后不再需要)
[Bb]in/
[Oo]bj/
如果使用自定义 ArtifactsPath,更新 .gitignore 条目以匹配。
对 Dockerfiles 的影响
复制构建输出的多阶段 Dockerfiles 必须引用新路径结构。见 [skill:dotnet-containers] 获取完整的 Dockerfile 模式。
传统路径:
COPY --from=build /app/src/MyApp/bin/Release/net10.0/publish/ .
构建输出路径:
COPY --from=build /app/artifacts/publish/MyApp/release/ .
Dockerfile 路径的关键差异:
- 输出在
artifacts/publish/下,而不是bin/Release/<tfm>/publish/ - 项目名称成为输出类型下的子目录
- 配置枢轴是小写(
release而不是Release) - TFM 在单目标项目枢轴中被省略
对 CI 管道的影响
必须更新上传构建工件或引用输出路径的 CI 工作流。见 [skill:dotnet-gha-build-test] 获取完整的 CI 工作流模式。
GitHub Actions – 上传构建输出:
- name: 发布
run: dotnet publish src/MyApp/MyApp.csproj -c Release
- name: 上传工件
uses: actions/upload-artifact@v4
with:
name: app
path: artifacts/publish/MyApp/release/
GitHub Actions – 上传 NuGet 包:
- name: 打包
run: dotnet pack -c Release
- name: 上传包
uses: actions/upload-artifact@v4
with:
name: packages
path: artifacts/package/release/*.nupkg
Azure DevOps – 发布工件:
- script: dotnet publish src/MyApp/MyApp.csproj -c Release
displayName: '发布'
- task: PublishPipelineArtifact@1
inputs:
targetPath: 'artifacts/publish/MyApp/release/'
artifact: 'app'
迁移清单
在现有项目上启用构建输出布局时:
- 添加
UseArtifactsOutput到Directory.Build.props - 更新
.gitignore– 用artifacts/替换[Bb]in/和[Oo]bj/ - 更新 Dockerfiles – 将所有
COPY --from=build路径更改为使用artifacts/结构 - 更新 CI 管道 – 修复工件上传路径、测试结果路径和发布路径
- 更新本地脚本 – 修复任何引用
bin/或obj/路径的 shell 脚本 - 清理旧输出 – 删除所有项目中现有的
bin/和obj/目录 - 验证构建 – 运行
dotnet build和dotnet publish以确认输出出现在artifacts/下 - 验证测试 – 运行
dotnet test以确认测试在新路径下执行
常见陷阱
- 不要在单目标项目的构建输出路径中硬编码 TFM。 单目标项目的枢轴仅是配置(例如
debug),而不是debug_net10.0。多目标项目在枢轴中包括 TFM。 - 不要在构建输出路径中使用大写的配置名称。 构建输出布局使用小写枢轴(
debug、release),而不是传统的大写名称(Debug、Release)。 - 不要假设
artifacts/package/有项目名称子文件夹。 与bin/、obj/和publish/不同,package/输出类型省略项目名称级别。包直接出现在artifacts/package/<config>/下。 - 不要在不先更新 Dockerfiles 和 CI 管道的情况下启用构建输出布局。 路径更改将破坏引用传统
bin/路径的COPY --from=build指令和工件上传步骤。 - 不要将构建输出布局呈现为默认的 .NET 布局。 自 .NET 8 起它是可选的,并且保持可选。推荐用于新项目;对于现有项目,根据好处评估迁移努力。