
使用 global.json paths 在项目内本地安装 .NET SDKsetup-local-sdk 完整实战指南【免费下载链接】skillsRepository for skills to assist AI coding agents with .NET and C#项目地址: https://gitcode.com/GitHub_Trending/skills17/skills导读本文基于plugins/dotnet/skills/setup-local-sdk/SKILL.md的核心方法论结合本仓库GitHub_Trending/skills17/skills中该 skill 的配套测试与真实配置系统讲解如何把 .NET SDK 安装进项目目录下的.dotnet/文件夹并通过 .NET 10 新增的global.jsonpaths特性把它接入 SDK 解析链。读完本文你将掌握安全尝试 .NET 预览版、精确锁定某个 SDK 版本、在 preview 上安装 MAUI 等 workload、为团队编写可复现的安装脚本以及如何在不触碰系统级安装的前提下随时回滚。一、这个 skill 解决什么问题setup-local-sdk是 dotnet 插件 提供的核心开发技能之一其目标非常明确把 .NET SDK 安装到项目本地的.dotnet/目录并通过global.json的paths特性.NET 10把它接入 SDK 解析。示例默认使用 .NET 11但该流程对任何版本——无论是 prerelease 还是 stable——都同样适用。本地安装带来的三个关键收益不修改系统级 .NET 安装——预览版、实验版不会污染全局环境从项目根目录执行dotnet命令时会自动命中本地 SDK删除即可回滚rm -rf .dotnet/macOS/Linux或Remove-Item -Recurse -Force .\.dotnetWindows。何时不要使用本技能该 skill 明确划定了边界SKILL.md场景原因用户需要系统级安装应直接引导到官方安装器宿主dotnet低于 v10paths特性不存在需解释并停止用户需要runtime-only安装paths只作用于 SDK 解析与运行时无关二、输入与前置条件skill 定义了两类输入参数输入必填默认值说明Channel 或版本号否11.0例如11.0、STS、LTS或精确版本如11.0.100-preview.2.26159.112Quality否preview取值之一daily、preview、gajq否—bash 团队脚本在修补已有global.json时需要没有 jq 时不要覆盖文件前置条件Prerequisites全局已安装 .NET 10 SDK——运行dotnet --version主版本号 ≥ 10。仓库中 dotnet 插件 自身就钉在10.0.100rollForward: latestMajor而仓库根目录的 global.json 则钉在11.0.100-preview.3.26207.106——这恰好印证了宿主用 10、项目内用 11 preview的典型组合。curlmacOS/Linux或PowerShellWindows可用。三、完整工作流12 步搭建本地 SDKStep 1 — 澄清要装什么如果用户没有指定先问清想要的版本例如最新的 .NET 11 preview或精确版本号。然后把回答映射到--channel/--quality或--version参数上。Step 2 — 校验 .NET 10 宿主如果用户已提供dotnet --version输出以该输出为准不要用 Agent 工作区的版本覆盖它两者不一致时向用户说明差异继续按用户机器的版本给出建议。dotnet --version若主版本 10在任何下载动作之前停下来paths特性要求 .NET 10 宿主 SDK。应告知用户先系统级安装 .NET 10 或更高版本再回到本地 SDK 配置流程。这一约束在配套测试中有明确验证eval.yaml 的第一个刺激场景模拟用户报告9.0.306要求 Agent 判定低于 .NET 10 要求、解释必须 .NET 10 才能用 paths并且不得输出任何--install-dir、dotnet-install.sh/ps1之类的安装命令。Step 3 — 检测操作系统运行uname -s 2/dev/null如果成功包括MINGW*、MSYS*、CYGWIN*这类 Git Bash 环境→ 使用 bash /dotnet-install.sh如果失败未装 Git Bash 的原生 Windows→ 使用 PowerShell /dotnet-install.ps1。Step 4 — 检查是否已有本地 SDKmacOS / Linuxtest -d .dotnet echo exists || echo not foundWindows (PowerShell)if (Test-Path -LiteralPath .\.dotnet) { exists } else { not found }若.dotnet/已存在询问用户用新版本更新还是跳过并保留现有版本Step 5 — 下载并运行安装脚本macOS / LinuxbashINSTALL_SCRIPT$(mktemp ${TMPDIR:-/tmp}/dotnet-install.XXXXXX) trap rm -f $INSTALL_SCRIPT EXIT curl -fsSL https://dot.net/v1/dotnet-install.sh -o $INSTALL_SCRIPT bash $INSTALL_SCRIPT --channel CHANNEL --quality QUALITY --install-dir .dotnetWindows (PowerShell)$installScript Join-Path $env:TEMP dotnet-install-$([guid]::NewGuid()).ps1 try { Invoke-WebRequest -Uri https://dot.net/v1/dotnet-install.ps1 -OutFile $installScript $installScript -Channel CHANNEL -Quality QUALITY -InstallDir .dotnet } finally { if (Test-Path -LiteralPath $installScript) { Remove-Item -LiteralPath $installScript -Force } }需要精确版本时用--version VERSIONbash或-Version VERSIONPowerShell替代 channel/quality 参数。两个脚本都来自微软官方地址https://dot.net/v1/dotnet-install.sh与https://dot.net/v1/dotnet-install.ps1。临时脚本用trap/finally保证执行后自动清理。Step 6 — 确认已安装的版本号./.dotnet/dotnet --version # macOS/Linux .\.dotnet\dotnet.exe --version # Windows记录下精确的版本字符串例如11.0.100-preview.2.26159.112它将写进global.json。仓库测试夹具中使用的是11.0.100-preview.3.26207.106见 tests/dotnet/setup-local-sdk/fixtures/global.json。Step 7 — 创建或更新 global.json{ sdk: { version: INSTALLED_VERSION, allowPrerelease: true, rollForward: latestFeature, paths: [.dotnet, $host$], errorMessage: Required .NET SDK not found. Run ./install-dotnet.sh (or .ps1) to install it locally. } }各字段含义与使用要点paths.dotnet放在前面表示本地优先$host$是系统级安装的回退项rollForward: latestFeature用于 latest-preview 或浮动 feature band 安装精确版本请求使用rollForward: disable避免 SDK 解析漂移到其他 feature bandallowPrerelease仅当安装 prerelease SDK 时设为truestable 版本应省略errorMessage仅当创建了团队安装脚本Step 10时包含否则省略。若global.json已存在必须谨慎合并先读取现有文件只新增/更新sdk对象保留msbuild-sdks、tools等其他属性然后写回——这样不会丢失跨项目配置如 MSBuild 设置。修改前务必备份原文件例如global.json.bak。最简配置无需版本钉定时{sdk:{paths:[.dotnet,$host$]}}仓库实测配套测试夹具中的 global.json 同时含有sdk、msbuild-sdksExample.Sdk: 1.2.3和toolsdotnet-example: 4.5.6三段测试明确要求合并后全部保留——这正是合并而非覆盖的实证。Step 8 — 更新 .gitignoremacOS / Linux或 Git Bashgrep -qxF .dotnet/ .gitignore 2/dev/null || printf \n.dotnet/\n .gitignoreWindows (PowerShell)if (-not (Test-Path .gitignore) -or -not (Select-String -Path .gitignore -Pattern ^\.dotnet/$ -Quiet)) { Add-Content -Path .gitignore -Value .dotnet/ }让.dotnet/永远不进版本库这是本地 SDK 不污染仓库的关键一步。Step 9 — 按需安装 workloads务必在global.json与.gitignore都完成后才做这一步这样即便 workload 安装缓慢或受平台限制基础本地 SDK 也已可用。若用户提到 MAUI、mobile、workload、Blazor WASM 或跨平台用本地二进制安装无需 sudo./.dotnet/dotnet workload install workload # macOS/Linux .\.dotnet\dotnet.exe workload install workload # Windows验证./.dotnet/dotnet workload list或.\.dotnet\dotnet.exe workload list。MAUI 注意要选当前 OS 与目标平台支持的 workload。Linux 上没有完整的mauimeta-workload目标为 Android 时可用maui-android否则应说明平台限制并询问要配置哪个目标。务必始终使用本地 dotnet 二进制执行 workload 命令。Workload 元数据相对于宿主进程的 dotnet 根目录存储用系统dotnet会把元数据放到错误位置参见 dotnet/sdk#49825。Step 10 — 创建团队安装脚本当用户提到 team、share、CI、scripts 等关键词时创建否则主动提出。脚本要备份global.json并保留已有配置。bash 脚本在需要修补已有global.json时依赖jq若jq不可用脚本拒绝覆盖文件只打印需要手动合并的配置。脚本变量需适配 Step 1 的安装选择精确版本应使用--version/-Version与rollForward: disablechannel 安装用 channel/quality且仅在 prerelease SDK 时设置allowPrerelease: true。若global.json已钉住sdk.version而用户主要是要脚本可直接复用该版本号并先更新global.json不要为了探知版本而启动一次漫长的 SDK 下载。当用户同时要 setup 和脚本时先创建脚本/配置再做长时安装确保即使下载或 workload 安装很慢可复现的配置也已就位。install-dotnet.shbash#!/usr/bin/env bash set -euo pipefail INSTALL_DIR.dotnet CHANNEL11.0 QUALITYpreview VERSION ROLL_FORWARDlatestFeature ALLOW_PRERELEASEtrue WORKLOADS(${}) ERROR_MESSAGERequired .NET SDK not found. Run ./install-dotnet.sh (or .ps1) to install it locally. INSTALL_SCRIPT$(mktemp ${TMPDIR:-/tmp}/dotnet-install.XXXXXX) GLOBAL_JSON_TMP cleanup() { rm -f $INSTALL_SCRIPT [ -n $GLOBAL_JSON_TMP ] rm -f $GLOBAL_JSON_TMP } trap cleanup EXIT curl -fsSL https://dot.net/v1/dotnet-install.sh -o $INSTALL_SCRIPT INSTALL_ARGS(--install-dir $INSTALL_DIR) if [ -n $VERSION ]; then INSTALL_ARGS(--version $VERSION) ROLL_FORWARDdisable else INSTALL_ARGS(--channel $CHANNEL --quality $QUALITY) fi bash $INSTALL_SCRIPT ${INSTALL_ARGS[]} SDK_VERSION$($INSTALL_DIR/dotnet --version) write_global_json() { if [ -f global.json ]; then cp global.json global.json.bak if ! command -v jq /dev/null 21; then echo global.json exists; install succeeded, but this script will not overwrite it without jq. 2 echo Merge these sdk settings manually so existing global.json properties are preserved: 2 cat 2 EOF { sdk: { version: $SDK_VERSION, allowPrerelease: $ALLOW_PRERELEASE, rollForward: $ROLL_FORWARD, paths: [.dotnet, \$host\$], errorMessage: $ERROR_MESSAGE } } EOF exit 1 fi GLOBAL_JSON_TMP$(mktemp ${TMPDIR:-/tmp}/global-json.XXXXXX) jq --arg version $SDK_VERSION --arg rollForward $ROLL_FORWARD --argjson allowPrerelease $ALLOW_PRERELEASE --arg errorMessage $ERROR_MESSAGE .sdk ((.sdk // {}) { version: $version, allowPrerelease: $allowPrerelease, rollForward: $rollForward, paths: [.dotnet, $host$], errorMessage: $errorMessage }) global.json $GLOBAL_JSON_TMP mv $GLOBAL_JSON_TMP global.json GLOBAL_JSON_TMP else cat global.json EOF { sdk: { version: $SDK_VERSION, allowPrerelease: $ALLOW_PRERELEASE, rollForward: $ROLL_FORWARD, paths: [.dotnet, \$host\$], errorMessage: $ERROR_MESSAGE } } EOF fi } write_global_json grep -qxF .dotnet/ .gitignore 2/dev/null || printf \n.dotnet/\n .gitignore [ ${#WORKLOADS[]} -gt 0 ] $INSTALL_DIR/dotnet workload install ${WORKLOADS[]} echo Done. SDK: $SDK_VERSIONchmod x install-dotnet.shinstall-dotnet.ps1PowerShellparam([string[]]$Workloads ()) $ErrorActionPreference Stop $installDir .dotnet; $channel 11.0; $quality preview $version ; $rollForward latestFeature; $allowPrerelease $true $errorMessage Required .NET SDK not found. Run ./install-dotnet.sh (or .ps1) to install it locally. $installScript Join-Path $env:TEMP dotnet-install-$([guid]::NewGuid()).ps1 try { Invoke-WebRequest -Uri https://dot.net/v1/dotnet-install.ps1 -OutFile $installScript $installArgs (-InstallDir, $installDir) if ($version) { $installArgs (-Version, $version) $rollForward disable } else { $installArgs (-Channel, $channel, -Quality, $quality) } $installScript installArgs } finally { if (Test-Path -LiteralPath $installScript) { Remove-Item -LiteralPath $installScript -Force } } $sdkVersion $installDir\dotnet.exe --version $globalJson if (Test-Path global.json) { Copy-Item global.json global.json.bak Get-Content -Path global.json -Raw | ConvertFrom-Json } else { [pscustomobject]{} } if (-not $globalJson.PSObject.Properties[sdk]) { $globalJson | Add-Member -MemberType NoteProperty -Name sdk -Value ([pscustomobject]{}) } $updates [ordered]{ version $sdkVersion allowPrerelease $allowPrerelease rollForward $rollForward paths (.dotnet, $host$) errorMessage $errorMessage } foreach ($entry in $updates.GetEnumerator()) { $property $globalJson.sdk.PSObject.Properties[$entry.Key] if ($property) { $property.Value $entry.Value } else { $globalJson.sdk | Add-Member -MemberType NoteProperty -Name $entry.Key -Value $entry.Value } } $globalJson | ConvertTo-Json -Depth 10 | Set-Content -Path global.json -Encoding UTF8 if (-not (Test-Path .gitignore) -or -not (Select-String -Path .gitignore -Pattern ^\.dotnet/$ -Quiet)) { Add-Content -Path .gitignore -Value .dotnet/ } if ($Workloads.Count -gt 0) { $installDir\dotnet.exe workload install Workloads } Write-Host Done. SDK: $sdkVersion把这两个脚本提交进仓库队友克隆后即可一键复现。注意脚本不修改 PATH没有export PATH/$env:PATHSDK 解析完全靠global.json paths——配套测试 eval.yaml 的第二、三个场景明确校验了这一点要求install*.sh/install*.ps1中不得包含export PATH或$env:PATH。Step 11 — 验证 SDK 解析dotnet --version输出应与本地安装版本一致。若不一致依次排查global.json的位置、paths数组内容、宿主 dotnet 版本是否 ≥ 10。Step 12 — 总结并说明清理方式向用户交代SDK 已安装、global.json已配置、.dotnet/已加入 gitignore、系统安装未被触碰。清理步骤删除.dotnet/从global.json移除paths/errorMessage按需删除安装脚本。最后附上最终的global.jsonsdk值或简短片段让用户能看到配置的版本、paths与errorMessage若安装了 workloads附上使用的本地dotnet workload install ...命令与验证结果或确切说明 workload 未能安装的阻塞原因。四、常见坑位速查坑位原因修复paths被忽略宿主dotnet v10系统级安装 .NET 10解析到了错误的 SDKglobal.json在父目录沿目录树向上检查global.json队友报 SDK not found.dotnet/被 gitignore 且没人跑过安装脚本在global.json中使用errorMessageworkloads 缺失用了系统dotnet而非本地二进制使用./.dotnet/dotnet workload installdotnet app.dll运行时不对paths只作用于 SDK 解析不影响 apphost改用dotnet run或设置DOTNET_ROOT最后一条尤其值得展开global.json的paths只影响SDK 的解析不会改变应用运行时所指向的 host/apphost。如果项目里出现SDK 是本地 11、跑起来却用了别的运行时的割裂现象问题不在 SDK 解析而在于运行时定位——这正是该 skill 在 When NOT to use 里强调 runtime-only 场景不适用paths的原因。五、在仓库中的配套验证与真实落点setup-local-sdk并非纸面方案仓库为其提供了完整的可执行评测capability 类型超时 10 分钟见 tests/dotnet/setup-local-sdk/eval.yaml共三个刺激场景检测不兼容的 .NET 宿主版本用户报告9.0.306评测要求 Agent 指出低于 .NET 10 门槛、解释paths需要 .NET 10、建议先系统级升级且全程不得出现安装命令创建团队安装脚本给定一个含sdkmsbuild-sdkstools三段配置的 global.json要求产出install*.sh/install*.ps1、写入paths与errorMessage、保留msbuild-sdks与tools原值、不修改 PATH只规划不下载用户要求给出精确命令与配置但禁止任何下载动作评测校验输出包含dotnet-install、global.json、.dotnet、paths、.gitignore且不得包含export PATH/setx PATH之类的 PATH 修改。这些场景逐条对应本文 Step 2、Step 7、Step 8、Step 10 的硬性要求也从侧面印证了该 skill 的评测设计原则——可复现、可清理、不污染系统、不破坏既有配置。若要深入了解本仓库其他 .NET skill 的写法与评测体系可继续阅读 plugins/dotnet/README.md 与 dotnet-skills.experiment.yaml。结语本地安装 SDK global.json paths的组合是把系统级环境和项目级环境彻底解耦的现代 .NET 团队协作方式预览版随便试、版本精确钉、队友一键复现、删除即回滚。从 Step 1 的版本澄清到 Step 12 的清理说明配合文中两个可直接落地的跨平台安装脚本你现在已经拥有一套完整、可复现、经过评测验证的项目本地 SDK 搭建方案。【免费下载链接】skillsRepository for skills to assist AI coding agents with .NET and C#项目地址: https://gitcode.com/GitHub_Trending/skills17/skills创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考