(4/30)大家一起學Blazor:Component及路由介紹

(4/30)大家一起學Blazor:Component及路由介紹

由於筆者當初是用ASP.NET Core API + Blazor Server,所以會以Blazor Server示範,日後研究完Blazor WebAssembly會再將心得補上。

最後更新 2021/12/10 下午11:01
StrayaWorker
預計閱讀 5 分鐘
分類
Blazor
專題
一起學Blazor系列
標籤
.NET C# ASP.NET Core Blazor

由於筆者當初是用 ASP.NET Core API + Blazor Server,所以會以 Blazor Server 示範,日後研究完 Blazor WebAssembly 會再將心得補上。

首先既然 Component 是可以重複利用的,我們在 Index.razor 放上兩個 Counter,啟動專案(如果不想完整偵錯,可以按 Ctrl+F5,就會啟動不偵錯模式,啟動速度比較快,而且每次儲存檔案,Blazor 都會監測到,網頁重新載入就可以載入新程式了),瀏覽器上兩個 Counter 有各自的 Click me 按鈕,分別點擊後可以看到數字分別增加,代表是不同的 Component,那這些數字又定義在哪裡呢?

打開 Counter.razor,最上面是@page 指示詞,這個稍後再說。再來是 HTML 跟一些 C# 程式,最後是@code 區塊,這就是 Blazor 的奇妙之處了,@code 相當於一般網頁 JS 做的事情,諸如定義變數、實作方法、發送 request 到後端或是 API,不過 Blazor 用 C# 編寫,這裡定義了一個私有變數 currentCount,還有一個方法 IncrementCount(),呼叫這方法的是 Click me 按鈕,每一次點擊按鈕都會使 currentCount+1,而呈現結果就在 p 元素內。

Index.razor和Counter.razor

兩個Counter獨立

currentCount 定義的方式跟頁面呈現就是一種模型綁定(model binding),意思是資料跟頁面有綁定關係,.NET Framework 的 View 的@model 或是@Viewbag,Angular 的[(ngModel)]也是同理,都是要做到資料流到頁面後,對頁面操作可以影響資料的行為。

我們來定義另一個變數 myClass,給這變數一些 bootstrap 的 class,再把變數放在 button 的 class 裡面,記住在 HTML 裡面用到 C# 的程式必須以@開頭,不然 Blazor 不知道要編譯。重新載入頁面可以看到按鈕的樣式變了,Blazor 幫我們把 myClass 的值 text-primary bg-warning 放進 button 的 class。

新增myClass到Counter按鈕

接著我們看 FetchData.razor,這裡看到了@using BlazorServer.Data,我們待會可以把這個 using 放進_import.razor,那麼@inject WeatherForecastService ForecastService 又是什麼呢?我們先看@code 區塊,看到這裡定義了 WeatherForecast 陣列型別的變數 forecasts,且用非同步方法 OnInitializedAsync 呼叫了 ForecastService.GetForecastAsync(DateTime.Now),將結果回傳 forecasts,眼尖的人應該發現了最上面的 ForecastService 跟@code 區塊的 ForecastService 一模一樣。

FetchData.razor

我們點一下 GetForecastAsync() 方法並按下 F12,可以看到這個方法回傳的就是 5 個隨機產生的天氣資料陣列,HTML 裡有判斷 forecasts 是否為 null,不是的話就產生一個 table,裡面用 foreach 將 forecasts 的日期、攝氏、華氏及天氣狀態一一呈現出來。

Service生成資料及渲染

前面說過 Blazor 只有一個網頁,其他內容都是一個個 Component 組成的,每次觸發事件,Server 或是 WebAssembly 都會將對應 Component 呈現在瀏覽器上,但 Blazor 怎麼知道現在要呈現哪個 Component 呢?

原因就是@page 指示詞,這個指示詞相當於傳統的路由,可以看到 Index.razor 的@page 為"/",表示這是首頁,Counter.razor 及 FetchData.razor 也有相應的@page 指示詞。一個頁面可以有多個@page 指示詞,不過開頭一定要有斜線且用雙引號包起來,筆者曾想過建立 enum 集中管理不同 Component 的@page,可惜目前 Blazor 不支援這種做法。另外若兩個 Component 用了相同的@page,編譯階段就會出現錯誤提示,所以也不用擔心若有重複路由 Blazor 會怎麼處理。

@page指示詞

那麼左邊選單的 Home, Counter, Fetch data 頁面又是在哪裡定義的呢?打開 MainLayout.razor,可以看到 NavMenu 元素,再打開 NavMenu.razor,可以看到三個 NavLink Component,這些 Component 會被 Server 翻譯為瀏覽器認識的 a 元素,因此就算我們打開 Dev tool,也只會看到 a 元素。

左側選單

左側選單在HTML呈現為a標籤1

左側選單在HTML呈現為a標籤2

回到 MainLayout.razor,可以看到@Body 指示詞,這就是其他 Component 會放置的地方,可以說是種 placeholder,再看 App.razor 裡面有 Found 及 NotFound 兩個 Component,從字面看就知道,前者是當輸入的網址找到匹配的 Component 則會進入這裡,後者則是找不到匹配的 Component,可以看到兩者都用了 MainLayout。另外若有不同頁面要套用不同 Layout,也可以自己定義。

@body

說到這裡,我們複習一下 Blazor Server 是怎麼走的,可以看到跟 Angular 類似都是一層一層往下,管理較為方便。Blazor WebAssembly 跟 Blazor Server 的 index.html 跟_Layout.cshtml 大致相等,以及缺少了 appsettings.json 檔案,通常會將程式跟資料庫連線需要的連線字串放在這個檔案,可證 Blazor WebAssembly 確實只是被動接收資料,而無法主動跟資料庫連線,筆者曾試過在這裡引用 EF Core,也是無法讓 Blazor WebAssembly 接觸資料庫,在.NET Framework 的世界是用 XML 格式的 web.config,在.NET Core 則改用 JSON 格式的 appsettings.json。

引用: ASP NET Core blazor project structure

註:本文程式碼透過 .NET 6 + Visual Studio 2022 重構,可點擊原文連結與重構後程式碼比較學習,謝謝閱讀,支持原作者

繼續探索

延伸閱讀

更多文章
同分類 / 同標籤 2021/12/25

(29/30)大家一起學Blazor:Blazor單元測試

開發一個系統最無聊的過程大概就是解決 Bug 了,尤其是那種嘗試對 null 物件取值的錯誤(`Object reference not set to an instance of an object.`),這應該是大部分人剛踏入程式設計領域最常碰到的問題,為了從枯燥的解決 Bug 過程解脫,這篇就來介紹`單元測試`。

繼續閱讀
同分類 / 同標籤 2021/12/25

(28/30)大家一起學Blazor:Policy-based authorization

之前有說到`ASP.NET Core Identity` 使用的是基於`Claim` 的驗證,其實`ASP.NET Core Identity` 有不同類型的授權方式,最簡單的`登入授權`、`角色授權`、`Claim 授權`,但上述幾種都是以一種方式實現:原則授權(`Policy-based authorization`)。

繼續閱讀