.NET构建输出布局 dotnet-artifacts-output

.NET构建输出布局是.NET SDK的一项功能,用于将.NET项目的构建输出集中到一个目录中,简化项目管理和构建流程,便于CI/CD和Docker集成。关键词:.NET、构建输出、gitignore、Docker、CI/CD、.NET SDK、集中输出。

DevOps 0 次安装 0 次浏览 更新于 3/6/2026

名称: 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'

迁移清单

在现有项目上启用构建输出布局时:

  1. 添加 UseArtifactsOutputDirectory.Build.props
  2. 更新 .gitignore – 用 artifacts/ 替换 [Bb]in/[Oo]bj/
  3. 更新 Dockerfiles – 将所有 COPY --from=build 路径更改为使用 artifacts/ 结构
  4. 更新 CI 管道 – 修复工件上传路径、测试结果路径和发布路径
  5. 更新本地脚本 – 修复任何引用 bin/obj/ 路径的 shell 脚本
  6. 清理旧输出 – 删除所有项目中现有的 bin/obj/ 目录
  7. 验证构建 – 运行 dotnet builddotnet publish 以确认输出出现在 artifacts/
  8. 验证测试 – 运行 dotnet test 以确认测试在新路径下执行

常见陷阱

  1. 不要在单目标项目的构建输出路径中硬编码 TFM。 单目标项目的枢轴仅是配置(例如 debug),而不是 debug_net10.0。多目标项目在枢轴中包括 TFM。
  2. 不要在构建输出路径中使用大写的配置名称。 构建输出布局使用小写枢轴(debugrelease),而不是传统的大写名称(DebugRelease)。
  3. 不要假设 artifacts/package/ 有项目名称子文件夹。bin/obj/publish/ 不同,package/ 输出类型省略项目名称级别。包直接出现在 artifacts/package/<config>/ 下。
  4. 不要在不先更新 Dockerfiles 和 CI 管道的情况下启用构建输出布局。 路径更改将破坏引用传统 bin/ 路径的 COPY --from=build 指令和工件上传步骤。
  5. 不要将构建输出布局呈现为默认的 .NET 布局。 自 .NET 8 起它是可选的,并且保持可选。推荐用于新项目;对于现有项目,根据好处评估迁移努力。

参考文献