📟.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 必填字串已初始化
留言
張貼留言