.NET 小技 - dotnet watch 避免特定資料夾異動觸發重載
| | | 0 | |
寫 ASP.NET Core 時,我超愛用 dotnet watch 功能,.NET 會在網頁注入一段 JavaScript,一旦偵測到專案範圍的檔案異動,便會使用熱重載(Hot Reload)技術動態將異動結果套用到執行中的應用程式並重新載入網頁,能即時看到修改結果就是爽! 如果只是更新 .html、.js、.css 等靜態檔案自動重載看結果沒什麼了不起,但更新 .cs 不必編譯整個應用程式重新啟動,居然針對局部套用,堪稱黑魔法。(註:這個神奇功能始於 .NET 6)
但我使用 dotnet watch 測試常遇到一個小困擾,用個範例重現問題。
假設我有個 HTML 如下,網頁上有顆按鈕,按下會呼叫 AJAX 寫入資料到 ContentRoot ./data/data.txt 檔案,並在 <pre> 顯示一行訊息。理論上,這個網頁可連按多次,連續更新 ./data/data.txt 並在 <pre> 印出多行訊息:
<!DOCTYPE html>
<html>
<head>
<title>dotnet watch run Test</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<button onclick="updateServerFile()">Update Server File</button>
<pre id="msgs"></pre>
<script>
function appendMessage(msg) {
const pre = document.getElementById('msgs');
pre.textContent += msg + '\n';
}
function updateServerFile() {
fetch('/update-server-file', { method: 'POST' })
.then(response => {
if (response.ok) {
appendMessage('Update at ' + new Date().toLocaleTimeString('sv'));
}
});
}
</script>
</body>
</html>
Program.cs 的寫法如下,程式很短邏輯很單純不值一提:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
var indexHtmlPath = Path.Combine(app.Environment.ContentRootPath, "index.html");
app.MapGet("/", () => Results.Text(File.ReadAllText(indexHtmlPath), "text/html"));
var dataFolder = Path.Combine(app.Environment.ContentRootPath, "data");
if (!Directory.Exists(dataFolder)) Directory.CreateDirectory(dataFolder);
var dataPath = Path.Combine(dataFolder, "data.txt");
app.MapPost("/update-server-file", () =>
{
File.WriteAllText(dataPath, DateTime.Now.ToString());
return Results.Ok("Server file updated.");
});
app.Run();
用 dotnet run 測試,一切如預期:

但改用 dotnet watch 測試,會發現按鈕只能按一次,畫面就會變灰。原因是寫入 ./data/data.txt 動作會觸發檔案異動偵測,引起網頁重載,打亂了我們的測試計劃。

爬文查到幾種做法,像是在 .csproj 加入以下宣告:
<ItemGroup>
<Watch Remove="data\**\*" />
</ItemGroup>
<!-- 或是 -->
<ItemGroup>
<Content Update="data\**\*" Watch="false" />
</ItemGroup>
但我實測都沒成功,最後找到有效的做法是這個:
<PropertyGroup>
<DefaultItemExcludes>$(DefaultItemExcludes);data/**</DefaultItemExcludes>
</PropertyGroup>

Explains how dotnet watch triggers unwanted reloads when updating data files, and how to exclude folders (e.g., data/**) to avoid this issue.
Comments
Be the first to post a comment