依據 Roadmap,完成 ASP.NET Core 版網站 CPU 與記憶體即時監看雛型後的下一步,自然也是將功能從網站抽取成為獨立物件。之前研究 ASP.NET MVC 功能元件化時看到一個好東西 - Razor Class Library,可以將 Razor 元件 (.razor Razor Component,類似 WebForm 時代的 .ascx,用於 Blazor App)、View Component、Page、Controller、View 等 UI 元素封裝進獨立類別程式庫,跟上週我將 MVC 功能打包成可攜式元件做的事一模一樣,都在追求程式碼重複利用。差別在於我的 MVC 版靠自己土砲,在 ASP.NET Core 時代已內建專屬專案,爽度破錶。

要建立可重複使用的 ASP.NET Core UI,可開啟 Visual Studio 2019 從專案範本找到 Razor Class Library (RCL):

預設 RCL 只支援 Razor Component,我想把 Razor Page 包成物件,故要勾選「Support pages and views」:(一度考慮把監看網頁包成 Razor Component,但我想在 HTML 也能透過 IFrame 內嵌,故維持走 Razor Page 架構,Razor Component 留到下次再玩)

RCL 專案預設會以 Area 結構擺放 Razor Page,新建專案時會產生一個 Page1.cshtml 放在 Areas/MyFeature/Pages/Page1.cshtml。在這裡出現的 Razor Page,跟 MVC Controller 一樣,專案只需參照這個 DLL 便能自動將 /MyFeature/Page1 URL 路由導向 Page1.cshtml。依我的案例,上次雛型中的 WebStatsMonitor/Index.cshtml 要搬進 RCL 專案,可對映成 Areas/WebStatsMonitor/Index.cshtml。至於網頁需要的 .js、.ttf、.css 等靜態檔,有個天大好消息,RCL 直接支援靜態檔案的封裝與部置,不需要自己用 Embedded Resource 苦哈哈搞資源內嵌,也不必扯到 VirtualPathProvider。只要在類別專案建個 wwwroot 資料夾把檔案放進去,未來便可透過 ~/_content/ClasLibraryName/xxx.xxx 存取,超級方便。

也因為如此,Index.cshtml.cs 完全不需要修改,我只調了 Index.cshtml 中 jquery.min.js 及 webstats.css 的 URL,改成 ~/_content/WebStatsMonitorCore/... 其餘直接沿用:

@page
@model WebStatsMonitorCore.Areas.WebStatsMonitor.Pages.IndexModel
@{
}
<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Web CPU & Memory</title>
    <link href="~/_content/WebStatsMonitorCore/webstats.css" rel="stylesheet" />
</head>
<body>
    <div class="frame">
        <div class="row">
            <span class="hdr">CPU</span> <span class="field" id="cpuLoad"></span>
        </div>
        <div class="row">
            <span class="hdr">RAM</span> <span class="field" id="memUsage"></span>
        </div>
    </div>
    <script src="~/_content/WebStatsMonitorCore/jquery.min.js"></script>
    <script>
        $(function () {
            //TODO 實際運用時改走 SignalR/WebSocket 較有效率
            function refresh() {
                $.getJSON("@Url.Content("?handler=Stats")").done(function (res) {
                    var cpuCss = "";
                    var cpuValue = parseInt(res.CPU.replace("%"));
                    if (cpuValue > 85) cpuCss = "alert";
                    else if (cpuValue > 50) cpuCss = "warn";
                    $("#cpuLoad").text(res.CPU).attr("data-tag", cpuCss);
                    $("#memUsage").text(res.RAM);
                });
            }
            refresh();
            setInterval(refresh, 2000);
        });

    </script>
</body>
</html>

就這樣,開一個新 ASP.NET Core 專案,參照 WebStatsMonitorCore.dll,建一個 demo.html 用 Iframe 內嵌 /WebStatsMonior,薑薑薑薑~

多虧 RCL 支援,這次將 Razor Page 封裝成元件的程序比當初自己搞 MVC 元件化簡單許多,需要修改的地方很少。而親身體驗過土砲的搞剛,用起 RCL 格外有幸福感,它肯定是我未來開發 ASP.NET Core 共用 UI 元件的首選。

範例專案已放上 Github,歡迎自取參考。

Exmaple of how to convert a Razor page UI to standalone library with Razor class library.


Comments

Be the first to post a comment

Post a comment