最新国产好看的视频,伊人天堂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ù)端檢測(cè) → 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#熱重載的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • C#新手常犯的錯(cuò)誤匯總

    C#新手常犯的錯(cuò)誤匯總

    這篇文章主要介紹了C#新手常犯的錯(cuò)誤匯總,對(duì)于經(jīng)驗(yàn)豐富的C#程序員同樣具有很好的參考借鑒價(jià)值,需要的朋友可以參考下
    2014-08-08
  • 利用C#開發(fā)瀏覽器擴(kuò)展的全過程記錄

    利用C#開發(fā)瀏覽器擴(kuò)展的全過程記錄

    做web開發(fā)的同學(xué),經(jīng)常會(huì)用到各種chrome瀏覽器插件,那么我們寄幾怎么開發(fā)一個(gè)插件呢(其實(shí)是瀏覽器擴(kuò)展)?這篇文章主要給大家介紹了關(guān)于利用C#開發(fā)瀏覽器擴(kuò)展的相關(guān)資料,需要的朋友可以參考下
    2021-07-07
  • C# Winform 實(shí)現(xiàn)控件自適應(yīng)父容器大小的示例代碼

    C# Winform 實(shí)現(xiàn)控件自適應(yīng)父容器大小的示例代碼

    這篇文章主要介紹了C# Winform 實(shí)現(xiàn)控件自適應(yīng)父容器大小的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-03-03
  • VS2010寫的程序在自己電腦可以運(yùn)行、其他電腦上不能運(yùn)行的解決方案

    VS2010寫的程序在自己電腦可以運(yùn)行、其他電腦上不能運(yùn)行的解決方案

    自己用Visual Studio 2010 旗艦版寫了一個(gè)軟件,在自己電腦上運(yùn)行完全沒有問題,但是拷貝到其他人電腦上之后不管雙擊還是以管理身份運(yùn)行,均沒有反應(yīng),進(jìn)程管理器中相關(guān)進(jìn)程也只是一閃而過
    2013-04-04
  • C#微信公眾平臺(tái)開發(fā)之a(chǎn)ccess_token的獲取存儲(chǔ)與更新

    C#微信公眾平臺(tái)開發(fā)之a(chǎn)ccess_token的獲取存儲(chǔ)與更新

    這篇文章主要介紹了C#微信公眾平臺(tái)開發(fā)之a(chǎn)ccess_token的獲取存儲(chǔ)與更新的相關(guān)資料,需要的朋友可以參考下
    2016-03-03
  • C#?wpf嵌入winform控件的示例詳解

    C#?wpf嵌入winform控件的示例詳解

    wpf的強(qiáng)大界面能力,再加上winform的性能以及靈活性,那基本上什么界面都能夠做的很好,本文我們就來看看如何在C#?wpf中嵌入winform控件吧
    2024-03-03
  • C#實(shí)現(xiàn)遠(yuǎn)程連接ORACLE數(shù)據(jù)庫的方法

    C#實(shí)現(xiàn)遠(yuǎn)程連接ORACLE數(shù)據(jù)庫的方法

    這篇文章主要介紹了C#實(shí)現(xiàn)遠(yuǎn)程連接ORACLE數(shù)據(jù)庫的方法,通過自定義函數(shù)db_connection_test實(shí)現(xiàn)遠(yuǎn)程連接Oracle數(shù)據(jù)庫的功能,是非常實(shí)用的技巧,需要的朋友可以參考下
    2014-12-12
  • WPF輕松實(shí)現(xiàn)進(jìn)度條的示例代碼

    WPF輕松實(shí)現(xiàn)進(jìn)度條的示例代碼

    WPF中的ProgressBar控件用于表示任務(wù)進(jìn)度,適用于文件下載、數(shù)據(jù)處理等場(chǎng)景,本文將通過XAML和C#代碼展示如何創(chuàng)建一個(gè)基本的WPF進(jìn)度條,并演示如何通過事件處理程序更新進(jìn)度條的值來模擬耗時(shí)操作,感興趣的小伙伴跟著小編一起來看看吧
    2024-12-12
  • C#多線程Thread使用示例詳解

    C#多線程Thread使用示例詳解

    這篇文章主要為大家詳細(xì)介紹了C#多線程Thread使用示例,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-07-07
  • adonet基礎(chǔ)示例分享(adonet連接數(shù)據(jù)庫)

    adonet基礎(chǔ)示例分享(adonet連接數(shù)據(jù)庫)

    這篇文章主要介紹了adonet基礎(chǔ)示例分享(adonet連接數(shù)據(jù)庫),需要的朋友可以參考下
    2014-04-04

最新評(píng)論

晋城| 青冈县| 鄂托克旗| 台江县| 原平市| 中方县| 阿瓦提县| 桑植县| 剑河县| 香河县| 高清| 西青区| 古交市| 辽阳市| 土默特左旗| 高密市| 武平县| 云梦县| 曲周县| 巴青县| 康马县| 惠州市| 大洼县| 万盛区| 株洲县| 武义县| 南江县| 七台河市| 文水县| 陆河县| 望城县| 陵水| 泸西县| 准格尔旗| 萝北县| 射洪县| 建湖县| 奉新县| 丁青县| 故城县| 石景山区|