最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C# .NET基于PicoServer的Live?Reload實(shí)現(xiàn)熱重載的完整方案

 更新時(shí)間:2026年06月10日 08:30:09   作者:桔子雨  
這篇文章主要為大家詳細(xì)介紹了如何基于.NET實(shí)現(xiàn)的零配置熱重載服務(wù)器,通過文件監(jiān)控、防抖處理及WebSocket廣播等步實(shí)現(xiàn)熱重載,文中的示例代碼講解詳細(xì),有需要的可以了解下

.NET 是一個(gè)開源、跨平臺(tái)的開發(fā)平臺(tái),運(yùn)行穩(wěn)定,資源消耗低,AOT 編譯進(jìn)一步降低了交付體積。本文基于 .NET 10 實(shí)現(xiàn)一個(gè)零配置的熱重載服務(wù)器,核心代碼不到 50 行。

依賴安裝:dotnet add package PicoServer

一、熱重載的本質(zhì)

熱重載解決的問題:文件保存后瀏覽器自動(dòng)刷新。

  • 傳統(tǒng)流程:修改 → 保存 → 切換窗口 → F5(4 步)
  • 熱重載后:修改 → 保存(2 步)

核心流程:文件變更 → 服務(wù)端檢測 → WebSocket 推送 → 瀏覽器刷新

二、實(shí)現(xiàn)

2.1 文件監(jiān)控與防抖

using PicoServer;
using System.Timers;
using System.IO;

string staticRoot = "wwwroot";
var app = new WebAPIServer();

var watcher = new FileSystemWatcher(staticRoot)
{
    EnableRaisingEvents = true,
    IncludeSubdirectories = true
};

var timer = new System.Timers.Timer(200) { AutoReset = false };
timer.Elapsed += async (_, _) => await app.WsBroadcastAsync("reload");

void OnChange(object s, FileSystemEventArgs e)
{
    var name = Path.GetFileName(e.Name);
    if (string.IsNullOrEmpty(name) || name.StartsWith('.') || name.StartsWith('~'))
        return;  // 過濾 IDE 臨時(shí)文件
    
    timer.Stop();
    timer.Start();  // 200ms 內(nèi)無新事件才觸發(fā)
}

watcher.Changed += OnChange;
watcher.Created += OnChange;
watcher.Deleted += OnChange;
watcher.Renamed += OnChange;

防抖的必要性:一次保存操作可能觸發(fā) Changed、Created、Renamed 多個(gè)事件,防抖將其合并為一次廣播,避免頁面重復(fù)刷新。

2.2 WebSocket 廣播

app.enableWebSocket = true;
app.WsOnConnectionChanged = (_, _) => Task.CompletedTask;

PicoServer 開啟 WebSocket 后,通過以下方法廣播:

await app.WsBroadcastAsync("reload");

2.3 客戶端腳本注入

在返回 HTML 時(shí)自動(dòng)注入 WebSocket 客戶端代碼,開發(fā)者無需手動(dòng)添加:

if (filePath.EndsWith(".html", StringComparison.OrdinalIgnoreCase))
{
    var content = await File.ReadAllTextAsync(filePath);
    var script = """
        <script>
        new WebSocket('ws://'+location.host+'/ws-reload').onmessage = e => {
            if (e.data === 'reload') location.reload();
        };
        </script>
        """;
    
    content = content.Contains("</body>")
        ? content.Replace("</body>", script + "</body>")
        : content + script;
    
    await res.WriteAsync(content, "text/html");
}

2.4 路徑放行

/ws-reload 路徑需要交給 WebSocket 處理,靜態(tài)文件中間件應(yīng)放行:

if (path == "/ws-reload") return true;

三、完整示例

using PicoServer;
using System.Timers;

var app = new WebAPIServer();
app.enableWebSocket = true;
app.WsOnConnectionChanged = (_, _) => Task.CompletedTask;

string staticRoot = "wwwroot";
var watcher = new FileSystemWatcher(staticRoot) { EnableRaisingEvents = true };
var timer = new System.Timers.Timer(200) { AutoReset = false };
timer.Elapsed += async (_, _) => await app.WsBroadcastAsync("reload");
watcher.Changed += (s, e) => { timer.Stop(); timer.Start(); };

app.AddMiddleware(async (req, res) =>
{
    var path = req.Url?.AbsolutePath ?? "";
    if (path == "/ws-reload") return true;
    
    // 解析文件路徑
    var reqPath = path.TrimStart('/');
    if (string.IsNullOrEmpty(reqPath)) reqPath = "index.html";
    var filePath = Path.GetFullPath(Path.Combine(staticRoot, reqPath));
    
    // 安全檢查
    if (!filePath.StartsWith(staticRoot) || !File.Exists(filePath))
    {
        res.StatusCode = 404;
        await res.WriteAsync("Not Found");
        return false;
    }
    
    // HTML 文件:注入腳本后返回
    if (filePath.EndsWith(".html", StringComparison.OrdinalIgnoreCase))
    {
        var content = await File.ReadAllTextAsync(filePath);
        var script = """
            <script>
            new WebSocket('ws://'+location.host+'/ws-reload').onmessage = e => {
                if (e.data === 'reload') location.reload();
            };
            </script>
            """;
        content = content.Contains("</body>")
            ? content.Replace("</body>", script + "</body>")
            : content + script;
        await res.WriteAsync(content, "text/html");
    }
    else
    {
        // 非 HTML 文件:直接返回
        await res.SendFileAsync(filePath, false);
    }
    return false;
});

app.StartServer(8080);
Console.WriteLine("熱重載已啟動(dòng): http://localhost:8080");
await Task.Delay(Timeout.Infinite);

四、擴(kuò)展方向

  • CSS 熱更新:廣播 css 消息,客戶端僅刷新樣式鏈接
  • 多設(shè)備同步:局域網(wǎng)內(nèi)多端同時(shí)刷新
  • 差異化刷新:根據(jù)文件類型決定刷新策略(如 .css 增量更新,.cshtml 全頁刷新)

五、關(guān)于 AOT

熱重載工具本身也應(yīng)當(dāng)保持輕量。Node.js 工具鏈通常需要安裝運(yùn)行時(shí)并下載數(shù)百 MB 依賴。

通過 .NET AOT 編譯,整個(gè)熱重載服務(wù)器可打包為 4-10 MB 的單文件,無需安裝 .NET 運(yùn)行時(shí),拷貝即用。

六、總結(jié)

組件代碼量
文件監(jiān)控 + 防抖15 行
WebSocket 廣播1 行
腳本注入10 行
總計(jì)26 行

26 行代碼,解決開發(fā)中最頻繁的中斷問題。

以上就是C# .NET基于PicoServer的Live Reload實(shí)現(xiàn)熱重載的完整方案的詳細(xì)內(nèi)容,更多關(guān)于C#熱重載的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論

永修县| 连平县| 达州市| 长春市| 石阡县| 黑水县| 弥渡县| 米泉市| 孟村| 伊春市| 海南省| 潼关县| 新营市| 衡水市| 积石山| 清苑县| 子洲县| 石门县| 上饶市| 日照市| 辽阳县| 荃湾区| 天峨县| 荆门市| 鸡西市| 阿坝| 德昌县| 灵宝市| 苏尼特右旗| 永济市| 达州市| 甘肃省| 涞源县| 东山县| 循化| 婺源县| 屏边| 淅川县| 永仁县| 曲阳县| 顺平县|