温故知新,.Net Core遇见Blazor(FluentUI),属于未来的SPA框架
什么是Blazor
Blazor是一個使用.NET生成交互式客戶端WebUI的框架:
使用C#代替JavaScript來創建信息豐富的交互式UI。
共享使用.NET編寫的服務器端和客戶端應用邏輯。
將UI呈現為HTML和CSS,以支持眾多瀏覽器,其中包括移動瀏覽器。
與新式托管平臺(如Docker)集成。
基于.Net Core提供客戶端Web開發的優勢
使用.NET進行客戶端Web開發可提供以下優勢:
使用C#代替JavaScript來編寫代碼。
利用現有的.NET庫生態系統。
在服務器和客戶端之間共享應用邏輯。
受益于.NET的性能、可靠性和安全性。
在Windows、Linux和macOS上使用VisualStudio保持高效工作。
以一組穩定、功能豐富且易用的通用語言、框架和工具為基礎來進行生成。
Blazor組件
Blazor應用基于組件。Blazor中的組件是指UI元素,例如頁面、對話框或數據輸入窗體。
組件是內置到.NET程序集的.NET?C#類,它們用于:
定義靈活的UI呈現邏輯。
處理用戶事件。
可以嵌套和重用。
可作為Razor類庫或NuGet包共享和分發。
組件類通常以Razor標記頁(文件擴展名為.razor)的形式編寫。Blazor中的組件有時被稱為Razor組件。Razor是一種語法,用于將HTML標記與專為提高開發人員工作效率而設計的C#代碼結合在一起。借助Razor,可使用Visual Studio中的IntelliSense編程支持在同一文件中的HTML標記與C#之間切換。Razor Pages和MVC也使用Razor。與基于請求/響應模型生成的Razor Pages和MVC不同,組件專門用于處理客戶端UI邏輯和構成。
Blazor使用UI構成的自然HTML標記。下面的Razor標記演示了一個組件(Dialog.razor),它顯示一個對話框,并處理在用戶選擇按鈕時發生的事件:
<div class="card" style="width:22rem"><div class="card-body"><h3 class="card-title">@Title</h3><p class="card-text">@ChildContent</p><button @onclick="OnYes">Yes!</button></div> </div>@code {[Parameter]public RenderFragment ChildContent { get; set; }[Parameter]public string Title { get; set; }private void OnYes(){Console.WriteLine("Write to the console in C#! 'Yes' button selected.");} }在上述示例中,OnYes是由按鈕的onclick事件觸發的C#方法。對話框的文本(ChildContent)和標題(Title)由在其UI中使用此組件的下述組件提供。
使用HTML標記將Dialog組件嵌入到另一個組件中。在以下示例中,Index組件(Pages/Index.razor)使用前面的Dialog組件。標記的Title屬性向Dialog組件的Title屬性傳遞標題的值。Dialog組件的文本(ChildContent)由<Dialog>元素的內容設置。向Index組件添加Dialog組件后,Visual Studio中的IntelliSense可加快使用語法和參數補全進行開發的速度。
@page "/"<h1>Hello, world!</h1><p>Welcome to your new app. </p><Dialog Title="Learn More">Do you want to <i>learn more</i> about Blazor? </Dialog>在瀏覽器中訪問父級Index組件時,將呈現該對話框。當用戶選擇此按鈕時,瀏覽器的開發人員工具控制臺會顯示由OnYes方法編寫的消息:
組件呈現為瀏覽器文檔對象模型(DOM)的內存中表現形式,它被稱為“呈現樹”,用于以靈活高效的方式更新UI。
文檔對象模型 (DOM) 是HTML和XML文檔的編程接口。它提供了對文檔的結構化的表述,并定義了一種方式可以使從程序中對該結構進行訪問,從而改變文檔的結構,樣式和內容。DOM 將文檔解析為一個由節點和對象(包含屬性和方法的對象)組成的結構集合。簡言之,它會將web頁面和腳本或程序語言連接起來。
一個web頁面是一個文檔。這個文檔可以在瀏覽器窗口或作為HTML源碼顯示出來。但上述兩個情況中都是同一份文檔。文檔對象模型(DOM)提供了對同一份文檔的另一種表現,存儲和操作的方式。DOM是web頁面的完全的面向對象表述,它能夠使用如 JavaScript等腳本語言進行修改。
Blazor Web Assembly
Blazor Web Assembly是單頁應用(SPA)框架,用于使用.NET生成交互式客戶端Web應用。Blazor Web Assembly使用無插件或將代碼重新編譯為其他語言的開放式Web標準。Blazor Web Assembly適用于所有新式Web瀏覽器,包括移動瀏覽器。
通過WebAssembly(縮寫為wasm),可在Web瀏覽器內運行.NET代碼。Web Assembly是針對快速下載和最大執行速度優化的壓縮字節碼格式。Web Assembly是開放的Web標準,支持用于無插件的Web瀏覽器。
Web Assembly代碼可通過JavaScript(稱為JavaScript互操作性,通常簡稱為JavaScript互操作或JS互操作)訪問瀏覽器的完整功能。通過瀏覽器中的Web Assembly執行的.NET代碼在瀏覽器的JavaScript沙盒中運行,沙盒提供的保護可防御客戶端計算機上的惡意操作。
當Blazor Web Assembly應用生成并在瀏覽器中運行時:
C#代碼文件和Razor文件將被編譯為.NET程序集。
該程序集和.NET運行時將被下載到瀏覽器。
BlazorWebAssembly啟動.NET運行時,并配置運行時,以為應用加載程序集。BlazorWebAssembly運行時使用JavaScript互操作來處理DOM操作和瀏覽器API調用。
已發布應用的大小(其有效負載大小)是應用可用性的關鍵性能因素。大型應用需要相對較長的時間才能下載到瀏覽器,這會損害用戶體驗。Blazor Web Assembly優化有效負載大小,以縮短下載時間:
在中間語言(IL)裁邊器發布應用時,會從應用刪除未使用的代碼。
壓縮HTTP響應。
.NET運行時和程序集緩存在瀏覽器中。
Blazor托管模型
主要的Blazor托管模型在Web Assembly上的瀏覽器中運行客戶端。將Blazor應用、其依賴項以及.NET運行時下載到瀏覽器。應用將在瀏覽器線程中直接執行。UI更新和事件處理在同一進程中進行。應用資產作為靜態文件部署到可為客戶端提供靜態內容的Web服務器或服務中。
如果創建了Blazor Web Assembly應用進行部署,但沒有后端ASP.NET Core應用來為其文件提供服務,那么該應用被稱為獨立Blazor Web Assembly應用。如果創建了應用進行部署,但沒有后端應用來為其文件提供服務,那么該應用被稱為托管的Blazor Web Assembly應用。托管的Blazor Web Assembly Client應用通常使用WebAPI調用或SignalR(結合使用ASP.NET Core SignalR和Blazor)通過網絡與后端Server應用交互。
blazor.webassembly.js腳本由框架和句柄提供:
下載.NET運行時、應用和應用依賴項。
初始化運行應用的運行時。
Blazor Web Assembly托管模型具有以下優點:
沒有.NET服務器端依賴項。應用下載到客戶端后即可正常運行。
可充分利用客戶端資源和功能。
工作可從服務器轉移到客戶端。
無需ASP.NETCoreWeb服務器即可托管應用。無服務器部署方案可行,例如通過內容分發網絡(CDN)為應用提供服務的方案。
Blazor Web Assembly托管模型具有以下局限性:
應用僅可使用瀏覽器功能。
需要可用的客戶端硬件和軟件(例如WebAssembly支持)。
下載項大小較大,應用加載耗時較長。
.NET運行時和工具支持不夠完善。例如,.NETStandard支持和調試方面存在限制。
在傳統Web應用和單頁應用(SPA)之間選擇
Atwood 定律:任何能夠用JavaScript編寫的應用程序,最終必將用JavaScript編寫。- Jeff Atwood
目前可通過兩種通用方法來構建Web應用程序:在服務器上執行大部分應用程序邏輯的傳統Web應用程序,以及在Web瀏覽器中執行大部分用戶界面邏輯的單頁應用程序(SPA),后者主要使用WebAPI與Web服務器通信。也可以將兩種方法混合使用,最簡單的方法是在更大型的傳統Web應用程序中托管一個或多個豐富SPA類子應用程序。
何時使用傳統Web應用程序:
應用程序的客戶端要求簡單,甚至要求只讀。
應用程序需在不支持JavaScript的瀏覽器中工作。
團隊不熟悉JavaScript或TypeScript開發技術。
何時使用SPA:
應用程序必須公開具有許多功能的豐富用戶界面。
團隊熟悉JavaScript、TypeScript或Blazor Web Assembly開發。
應用程序已為其他(內部或公共)客戶端公開API。
此外,SPA框架還需要更強的體系結構和安全專業知識。相較于傳統Web應用程序,SPA框架需要進行頻繁的更新和使用新框架,因此改動更大。相較于傳統Web應用,SPA應用程序在配置自動化生成和部署過程以及利用部署選項(如容器)方面的難度更大。
使用SPA方法改進用戶體驗時必須權衡這些注意事項。
傳統Web應用程序、SPA或Blazor應用之間進行選擇時要考慮的一些基本因素
| 需要團隊熟悉 JavaScript/TypeScript | 最低 | 必需 | 最低 |
| 支持不帶腳本的瀏覽器 | 支持 | 不支持 | 支持 |
| 客戶端應用程序行為極少 | 適合 | 不必要 | 可行 |
| 豐富而復雜的用戶界面要求 | 受限 | 適合 | 適合 |
何時選擇傳統Web應用
應用程序的客戶端要求簡單,可能要求只讀
對許多Web應用程序而言,其大部分用戶的主要使用方式是只讀。只讀(或以讀取為主)應用程序往往比那些維護和操作大量狀態的應用程序簡單得多。例如,搜索引擎可能由一個帶有文本框的入口點和用于顯示搜索結果的第二頁組成。匿名用戶可以輕松提出請求,并且很少需要使用客戶端邏輯。同樣,一般而言,博客或內容管理系統中面向公眾的應用程序主要包含的內容與客戶端行為關系不大。此類應用程序容易構建為基于服務器的傳統Web應用程序,在Web服務器上執行邏輯,并呈現要在瀏覽器中顯示的HTML。事實上,網站的每個獨特頁面都有自己的URL,搜索引擎可以將其存為書簽和編入索引(默認設置,無需將此功能添加為應用程序的單獨功能),這也是此類情況的一個明顯優勢。
應用程序需在不支持JavaScript的瀏覽器中工作
如需在有限或不支持JavaScript的瀏覽器中工作的Web應用程序,則應使用傳統的Web應用工作流編寫(或至少可以回退到此類行為)。SPA需要客戶端JavaScript才能正常工作;如果沒有客戶端JavaScript,SPA不是好的選擇。
團隊不熟悉JavaScript或TypeScript開發技術
如果團隊不熟悉JavaScript或TypeScript,但熟悉服務器端Web應用程序開發,那相較于SPA,他們交付傳統Web應用的速度可能更快。除非以學習SPA編程為目的,或需要SPA提供用戶體驗,否則對已經熟悉構建傳統Web應用的團隊而言,選擇傳統Web應用的工作效率更高。
何時選擇SPA
應用程序必須公開具有許多功能的豐富用戶界面
SPA可支持豐富客戶端功能,當用戶執行操作或在應用的各區域間導航時無需重新加載頁面。SPA很少需要重新加載整個頁面,因此加載速度更快,可在后臺提取數據,并且對單個用戶操作的響應更快。SPA支持增量更新,可保存尚未完成的窗體或文檔,而無需用戶單擊按鈕提交窗體。SPA支持豐富的客戶端行為,例如拖放,比傳統應用程序更容易操作。可以將SPA設計為在斷開連接的模式下運行,對客戶端模型進行更新,并在重新建立連接后將更新最終同步回服務器。如果應用要求包括豐富的功能,且超出了典型HTML窗體提供的功能,則選擇SPA樣式應用程序。
通常,SPA需要實現內置于傳統Web應用中的功能,例如在反映當前操作的地址欄中顯示有意義的URL(并允許用戶將此URL存為書簽或對其進行深層鏈接以便返回此URL)。SPA還應允許用戶使用瀏覽器的后退和前進按鈕尋找用戶意料之中的結果。
團隊熟悉JavaScript和/或TypeScript開發
編寫SPA需要熟悉JavaScript或TypeScript以及客戶端編程技術和庫。團隊應有能力像使用Angular一樣使用SPA框架編寫新式JavaScript。
參考-SPA框架
Angular:https://angular.io
React:https://reactjs.org/
Vue.js:https://vuejs.org/
應用程序已為其他(內部或公共)客戶端公開API
如果已提供一個Web API供其他客戶端使用,則相較于在服務器端窗體中復制邏輯,創建一個利用這些API的SPA實現更加容易。用戶與應用程序交互時,SPA廣泛使用Web API來查詢和更新數據。
何時選擇Blazor
應用程序必須公開豐富用戶界面
與基于JavaScript的SPA一樣,Blazor應用程序可以支持豐富的客戶端行為,而無需重載頁面。這些應用程序對用戶的響應更快,僅獲取響應給定用戶交互所需的數據(或HTML)。如果設計得當,可以將服務器端Blazor應用配置為以客戶端Blazor應用的形式運行,只需在此功能受支持后對它進行稍加更改即可。
與使用JavaScript或TypeScript開發相比,團隊更喜歡使用.NET開發
與使用JavaScript或TypeScript等客戶端語言相比,許多使用.NET和Razor的開發人員的工作效率更高。由于已經使用.NET開發了應用程序的服務器端,因此,使用Blazor可以確保團隊中的每名.NET開發人員都可以理解,并可能會生成應用程序前端的行為。
Blazor Server
Blazor將組件呈現邏輯從UI更新的應用方式中分離出來。Blazor Server在ASP.NET Core應用中支持在服務器上托管Razor組件。可通過SignalR連接處理UI更新。
運行時停留在服務器上并處理:
執行應用的C#代碼。
將UI事件從瀏覽器發送到服務器。
將UI更新應用于服務器發送回的已呈現的組件。
Blazor Server用于與瀏覽器通信的連接還用于處理JavaScript互操作調用。
JavaScript互操作
對于需要第三方JavaScript庫和訪問瀏覽器API的應用,組件與JavaScript進行互操作。組件能夠使用JavaScript能夠使用的任何庫或API。C#代碼可調用到JavaScript代碼,而JavaScript代碼可調用到C#代碼。
在ASP.NET Core Blazor中從.NET方法調用JavaScript函數
https://docs.microsoft.com/zh-cn/aspnet/core/blazor/call-javascript-from-dotnet?view=aspnetcore-5.0
從ASP.NET Core Blazor中的JavaScript函數調用.NET方法
https://docs.microsoft.com/zh-cn/aspnet/core/blazor/call-dotnet-from-javascript?view=aspnetcore-5.0
Blazor支持的平臺
| Apple Safari,包括 iOS | 當前? |
| Google Chrome,包括 Android | 當前? |
| Microsoft Edge | 當前? |
| Mozilla Firefox | 當前? |
?最新指的是瀏覽器的最新版本。
Blazor模板選項
Blazor WebAssembly項目模板:blazorwasm
Blazor Server項目模板:blazorserver
創建我的第一個Blazor應用
1. 先準備".NET SDK (Software Development Kit)"環境。
如果之前沒有安裝的先安裝這個SDK:
dotnet-sdk-5.0.202-win-x64.exe
如果已經安裝過了,檢查下當前版本:
dotnet --version2. 根據Blazor項目模板創建應用
1) 命令行方式創建
dotnet new blazorserver -o BlazorApp --no-https這里通過DOTNET-CLI執行新建項目的命令,使用的是blazorserver這個項目模板,輸出項目文件夾為BlazorApp,給該項目設置為不需要HTTPS模式--no-https。
如果要創建Blazor WebAssembly項目,這里將blazorserver改成blazorwasm即可。
dotnet new blazorwasm -o BlazorApp --no-https2) Visual Studio方式創建
打開Visual Studio 2019最新版本,創建新項目,找到Blazor相關的項目模板。
Blazor Server應用
Blazor WebAssembly應用
點擊下一步,輸入BlazorApp的項目名稱,點擊下一步進行創建。
目標框架,可以選.NET Core 3.1(長期支持),也可以選擇.NET 5.0(當前),去掉勾選復選框配置HTTPS,點擊創建即可。
創建成功之后,會自動打開項目解決方案。
3. 運行應用
1) 命令行方式創建
如果通過命令行方式創建,運行應用只需要執行:
dotnet watch run通過DOTNET-CLI的Run命令可以運行程序,這里添加watch參數的好處就是,等下如果改動了文件,會熱重載,這樣調試起來就很方便。
運行起來之后,會看到瀏覽器彈出應用首頁。
如果要退出運行,只需要執行如下命令即可:
Ctrl + C2) Visual Studio方式創建
在Visual Studio里面運行就很簡單了,直接點運行BlazorApp或者Ctrl + F5即可。
默認會打開一個終端控制臺界面,用來顯示Console日志。
運行起來之后,會看到瀏覽器彈出應用首頁。
4. 項目結構
Program.cs?啟用這個應用服務的入口節點。
Startup.cs?配置應用服務和中間件的地方。
App.razor?應用組件的根組件,也就是組件的入口位置。
BlazorApp/Pages?包含一些示例頁面,也是頁面目錄。
BlazorApp.csproj?描述應用項目及其依賴關系。
5. 認識首頁及組件
我們看到Pages/Index.razor這個主頁。
@page "/"<h1>Hello, world!</h1>Welcome to your new app.<SurveyPrompt Title="How is Blazor working for you?" />這里已經有了SurveyPrompt這樣一個組件,同時它有一個入參Title可以定制。
6. 查看子組件計數器
打開Pages/Counter.razor,這是一個計數器的組件。
@page "/counter"<h1>Counter</h1><p>Current count: @currentCount</p><button class="btn btn-primary" @onclick="IncrementCount">Click me</button>@code {private int currentCount = 0;private void IncrementCount(){currentCount++;} }我們可以從代碼看到,頂部@page "/counter"實際上這個頁面組件的目錄,當我們切換到它時,路徑也會變化。
每次點擊Click me按鈕的時候,就會從onclick事件去找到IncrementCount這個函數,在這個函數中,我們把currentCount做了加1,這時候,Current count的值會跟著刷新,可以看出只要綁定好了數據,它就會幫我們自動去更新界面顯示了,還是很方便。
7. 在首頁添加子組件計數器
打開Pages/Index.razor,我們在末尾追加Counter即可。
@page "/"<h1>Hello, world!</h1>Welcome to your new app.<SurveyPrompt Title="How is Blazor working for you?" /><Counter />這時候,我們查看頁面就已經可以看到它了。
8. 修改組件添加屬性并使用
接下來,我們打開Pages/Counter.razor,我們給這個組件添加一個參數屬性IncrementAmount,默認值是1, 這樣我們可以從外部傳遞值進來修改它,并且我們讓currentCount不再是繼續加1了,而是改成加IncrementAmount的值,這樣我們就可以控制每次累加的幅度。
@page "/counter"<h1>Counter</h1><p>Current count: @currentCount</p><button class="btn btn-primary" @onclick="IncrementCount">Click me</button>@code {private int currentCount = 0;[Parameter]public int IncrementAmount { get; set; } = 1;private void IncrementCount(){currentCount += IncrementAmount;} }然后,我們回到Pages/Index.razor,在Counter組件上給他傳遞IncrementAmount的值進來。
@page "/"<h1>Hello, world!</h1>Welcome to your new app.<SurveyPrompt Title="How is Blazor working for you?" /><Counter IncrementAmount="10" />這時候,界面會自動重載,這時候,我們每次點擊Click me,這個計時器組件就會加10了,哈哈,是不是很簡單。
生成Blazor待辦事項列表應用
1. 先準備".NET SDK (Software Development Kit)"環境。
如果之前沒有安裝的先安裝這個SDK:
dotnet-sdk-5.0.202-win-x64.exe
如果已經安裝過了,檢查下當前版本:
dotnet --version2. 創建待辦事項列表Blazor應用
dotnet new blazorserver -o TodoList --no-https通過DOTNET-CLI腳本的New命令,新建一個blazorserver項目模板,輸出目錄命名為TodoList,同時不需要HTTPS的支持。
3. 添加名為“Todo”的Blazor組件
cd TodoList先切換到TodoList項目文件夾中。
dotnet new razorcomponent -n Todo -o Pages然后,通過DOTNET-CLI腳本的New命令,輸出目錄為Pages,新建名為Todo的razorcomponent組件。
其中-n全稱為--name,用來指定創建的名稱,-o全稱為--output,用來指定在這個目錄進行創建。
Razor組件文件名要求首字母大寫。打開Pages文件夾,確認Todo組件文件名以大寫字母T開頭。文件名應為Todo.razor。
將在項目文件夾的Pages目錄中,新建得到一個Todo.razor文件。
接下來,我們需要在Todo.razor文件頂部添加針對該文件組件的路由位置。
@page "/todo"4. 將“Todo”的Blazor組件添加到左側導航
位于Shared文件夾的NavMenu.razor組件是控制左側導航的,我們需要將“Todo”的Blazor組件添加到左側導航中。
在NavMenu.razor組件中,找到ul元素下的li節點,參考前面的例子,新建屬于Todo組件的導航位置。
<div class="@NavMenuCssClass" @onclick="ToggleNavMenu"><ul class="nav flex-column">...<li class="nav-item px-3"><NavLink class="nav-link" href="todo"><span class="oi oi-list-rich" aria-hidden="true"></span> ToDoList</NavLink></li></ul> </div>這里我們需要注意的幾個關鍵點是,NavLink的href需要填寫組件的路由位置,其中span元素是菜單圖標,緊跟著它的就是菜單名稱,這里我們用ToDoList來作為菜單名稱。
保存之后,我們通過執行run命令來運行,查看導航效果。
dotnet watch run5. 添加“TodoItem”來存儲待辦事項數據。
這里一個小插曲就是為了更好的寫出TodoItem.cs這個模型類,我遇到了兩個不錯的VSC插件,這里就順帶記錄一下。
名為C# Extensions的VSC插件,可以幫助我們支持在VSC中右鍵快速新建模型類和接口,有點類似VS中那種創建,至少幫你完成了當前命名空間的添加的活,所以值得推薦。
名為C# XML Documentation Comments的VSC插件,平時我們在VS中寫代碼,習慣性的如果要添加函數或者屬性的注釋的話,上來就是///然后等待自動完成得到一串添加注釋的注釋體,這個插件就是來干這個事情的,效果還不錯。
這兩個插件,搜索C#這個關鍵詞就可以看到了,基本上排在前面。
有了它們,我們創建TodoItem模型類就如虎添翼了。
在項目的Data文件夾中,我們右鍵,選擇New C# Class,輸入TodoItem,然后回車即可。
然后我們就自動完成,得到了一個基礎的空的TodoItem.cs模型類,它的namespace都是已經處理好了,我覺得比手寫強吧。
接下里,我們往TodoItem.cs模型類中添加兩個屬性(最好是走prop命令來新建),一個是Title來存儲待辦事項的標題,一個是IsDone來標記是否已完成該事項。
接下來,為了將來更好的閱讀這個模型,我們養成一個好習慣,給對應的模型和字段都添加好注釋,這時候C# XML Documentation Comments這個VSC插件就要派上用場了,通過在所需要注釋代碼的開頭位置,輸入///然后回車即可。
namespace TodoList.Data {/// <summary>/// 待辦事項/// </summary>public class TodoItem{/// <summary>/// 事項名稱/// </summary>/// <value></value>public string Title { get; set; }/// <summary>/// 事項是否已完成/// </summary>/// <value></value>public bool IsDone { get; set; }} }參考
ASP.NET Core Blazor 簡介
BlazorFluentUI
Blazor Webassembly Demo
DOM概述
在傳統 Web 應用和單頁應用 (SPA) 之間選擇
WebAssembly (abbreviated Wasm)
從 ASP.NET Core Blazor 中的 JavaScript 函數調用 .NET 方法
在 ASP.NET Core Blazor 中從 .NET 方法調用 JavaScript 函數
ASP.NET Core Blazor 托管模型
用于 ASP.NET Core Blazor 的工具
Blazor Tutorial - Build your first Blazor app
生成 Blazor 待辦事項列表應用
C# Extensions - VS MarketPlace
C# XML Documentation Comments - VS MarketPlace
總結
以上是生活随笔為你收集整理的温故知新,.Net Core遇见Blazor(FluentUI),属于未来的SPA框架的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 乐观锁与悲观锁各自适用场景是什么?
- 下一篇: .Net日志之nlog