📟.NET 8 專案 MSB3030「無法複製 appsettings.Development.json」:publish 巢狀遞迴的完整排錯與修正指南
重點摘要
-
你的
dotnet run/build報錯 MSB3030:找不到要複製的 appsettings.Development.json。 -
真正原因是:專案把
publish/(甚至out/)目錄也當成專案來源來「再發佈一次」,形成publish\publish-...\publish-...的無限巢狀與「來源檔不存在」。 -
兩步就好:
-
清掉殘留:刪除
bin/、obj/、publish/。 -
改 .csproj:加
DefaultItemExcludes排除publish/out,並「白名單」只處理根目錄的appsettings*.json,同時把bin/obj/publish/out從各 Items 移除。
-
問題現象(錯誤訊息)
你的主控台長這樣(節錄重點):
注意到那串超長路徑嗎?publish\publish-...\publish-... 一層套一層,就是自我遞迴的典型症狀。
為什麼會發生?
ASP.NET Core 的 Microsoft.NET.Sdk.Web 會「自動收錄」很多檔案(Default Items)。
如果你或某個外部共用設定(例如 Directory.Build.targets/props)有這類萬用字元:
-
**\*.json、**\*.* -
或自訂
<Copy>/AfterPublish把publish當「來源」 再複製一次
就可能把 上一次發佈產生的 publish/ 當作這次建置的來源,造成:
-
publish裡面又包含publish(無限巢狀) -
尋找「來源檔」時,路徑越疊越長、實際又不存在 → MSB3030
最快解法(保險且通用)
1) 先清乾淨
這次改用 CMD 指令 與跨平台清理,與上一版不同寫法
2) 修改 Net.csproj(重點設定)
新版寫法:同樣達到「排除 publish/out、白名單 appsettings」目標,但採用 Update + Exclude 與更完整的排除清單
3) 再建置 / 執行
這次示範加上 --no-restore(若前面已 restore)與 --urls,避免重複步驟
進階:想抓出真正「元兇」?(建議一次做)
改用 dotnet msbuild 的參數形式,輸出不同檔名,便於歸檔
用 MSBuild Structured Log Viewer 打開 build-diag.binlog,搜尋:
-
Copy任務 -
超長的
publish-...appsettings.Development.json路徑
往上展開,看是哪個 Item/Target 把publish/收進來。
參考:如果真的想「時間戳備份」發佈結果
全新示範:改以 robocopy 較快的備份方式,且路徑在專案外,杜絕遞迴
非 Windows 可改:<Exec Command="dotnet tool run copyfiles "$(PublishDir)**/*" "$(ArchiveRoot)"" />
或使用 PowerShell:
FAQ:常見疑問
Q1:為什麼 dotnet publish 先成功,後面 dotnet run 反而失敗?
A:第一次發佈把產物丟到 publish/。但下一次建置把 publish/ 當成來源又收進來,就會形成巢狀遞迴與找不到檔案 → MSB3030。
Q2:我可以用萬用字元 **/*.json 嗎?
可以,但一定要排除 bin/obj/publish/out/node_modules,例如以下 全新範例(與前述不同寫法):
Q3:appsettings.Development.json 需要發佈到正式環境嗎?
通常不需要。這裡也示範了另一種條件式寫法(不同於前例):
Q4:只 Clean 可以解決嗎?
請同時刪除 publish/,不然殘留的巢狀內容下次仍可能被收進來。
順手把 Nullability 警告也降噪一下(全新示範)
1) Model 的必填字串給預設值或 required
2) ToDictionary 的 Key 不能是 string?(替代策略:為 null 指定替代鍵)
3) Controller 參數加保護(改用 BindRequired 或手動驗證)
4) Minimal API 版本(另一種完全不同的寫法)
最後的檢查清單(不少團隊就靠這張)
-
.csproj已加<DefaultItemExcludes>…;**\publish\**;**\out\**</DefaultItemExcludes> -
已把
bin/obj/publish/out從Content/None/Compile/EmbeddedResource等 Items 移除 -
僅白名單處理
appsettings*.json(根目錄) -
刪除過
bin/、obj/、publish/後重新建置 -
沒有任何
<Copy>/自訂 Target 把publish/當成「來源」 -
若要時間戳備份,目的地在專案外的
artifacts/,不是publish/裡 -
ToDictionary的 key 不是string?;Model 必填字串已初始化
留言
張貼留言