Blazor第1天_Blazor Server跟Blazor WebAssembly專案種類與技術差異介紹
本次筆記學習皆以vs2019 .net 5以上版本做示範
會分別紀錄vs2019 .net5 與 vs2022 .net6的專案開發方式
如果專案本身有一些要跟.net framework以前的4.5左右相依
電腦空間有限
建議可以採用vs2019 與.net5的配套
https://docs.microsoft.com/zh-tw/visualstudio/releases/2019/compatibility
因為vs2022(才支援到.net6)會只支援到4.6(含)以上的版本
https://docs.microsoft.com/zh-tw/visualstudio/releases/2022/compatibility
Blazor的介紹
Blazor 其實就是Browser 加上以前的Razor語法 (Browser + Razor)
屬於一種基於.net core的 Single Page Application(SPA) 框架,因此可跨平台。
其實就是微軟有個野心想讓C#這個程式語言可以不只限於用在後端也可以將前端涵蓋。
Blazor主要包含以下幾項特色
Component-based 架構
Javascript Interop
Forms & Validation
Routing
State Management
Layouts
而Blazor主要又分為兩種Hosting Model
1.Blazor Server
2.Blazor WebAssembly
所謂Hosting Model
也就是所謂的Render這些
監聽UI變化的相應計算機制的Blazor component邏輯的模式
Blazor Server跟Blazor WebAssembly技術差異
Blazor Server技術介紹
主要會需要一個server,在Server上運行完並即時渲染到Browser的模式。
Blazor Server是一套底層藉由SignalR來當作Client Side與Server Side的溝通媒介
一些js dom或event trigger都會藉此技術來做交互。
(備註:SignalR 技術基本上就是一套底層透過websocket達到real-time的連線更動open source library)
Blazor Server 優點:
下載檔案較小
對於.net相關工具較有可運用性
Server運用性較多,程式也在Server端上。
Blazor Server 缺點:
有較高的延遲
不好Scalable
不支援Offline時候的運行
不可採用Serverless佈署
Blazor WebAssembly(WASM)技術介紹
WebAssembly
其實又可被縮減為WASM
是一種可被運行在modern web browser的low-level assembly-like language(二進位制指令)
底層技術上就是將被編譯過的程式轉譯為WASM最終下載到client-side的browser去運行
(所有程式經過編譯後的dll跟其他相關運行資源都會被下載到Browser運行)
撇除IE基本上比較新一點的Modern Web Browser都有支援
在Blazor WASM 應用中又有再針對開發導向是否有包含.net core後端
細分兩種型態
1.Standalone:不含asp.net core 後端
2.Hosted:含asp.net core 後端
Blazor WASM 優點:
不具有.net server-side相依性
對於Server Loading會較少
對於Client資源利用最大化,支援Offline時候的部分邏輯運行。
可採用Serverless佈署
Blazor WASM 缺點
網頁第一次Load會要Load可能比較久
(由於會把很多後端編譯好的dll跟程式檔下載到Client Browser,所以下載量較大。)
針對Browser具有是否支援的強依賴(如上述Browser支援)
專案新建方式
Blazor Server專案新建
基本上跟之前.net core mvc 或 .net core web api本身專案架構學習方式一樣
程式進入點
一定就是從Program.cs的Main開始
~\BlazorServerApp1\Program.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace BlazorServerApp1 { public class Program { public static void Main(string[] args) { CreateHostBuilder(args).Build().Run(); } public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); }); } } |
在Startup.cs程式中則是服務相關的注入和一些middleware配置
~\BlazorServerApp1\Startup.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | using BlazorServerApp1.Data; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace BlazorServerApp1 { public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container. // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 public void ConfigureServices(IServiceCollection services) { services.AddRazorPages(); services.AddServerSideBlazor(); services.AddSingleton<WeatherForecastService>(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/Error"); } app.UseStaticFiles(); app.UseRouting(); app.UseEndpoints(endpoints => { endpoints.MapBlazorHub(); endpoints.MapFallbackToPage("/_Host"); }); } } } |
在第51行的
endpoints.MapBlazorHub();
就是去建立SignalR與BlazorServerSide的連線溝通
在第52行的
endpoints.MapFallbackToPage("/_Host");
則是將所有Http 請求導向至
~\BlazorServerApp1\Pages\_Host.cshtml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | @page "/" @namespace BlazorServerApp1.Pages @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers @{ Layout = null; } <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>BlazorServerApp1</title> <base href="~/" /> <link rel="stylesheet" href="css/bootstrap/bootstrap.min.css" /> <link href="css/site.css" rel="stylesheet" /> <link href="BlazorServerApp1.styles.css" rel="stylesheet" /> </head> <body> <component type="typeof(App)" render-mode="ServerPrerendered" /> <div id="blazor-error-ui"> <environment include="Staging,Production"> An error has occurred. This application may no longer respond until reloaded. </environment> <environment include="Development"> An unhandled exception has occurred. See browser dev tools for details. </environment> <a href="" class="reload">Reload</a> <a class="dismiss">🗙</a> </div> <script src="_framework/blazor.server.js"></script> </body> </html> |
第33行引入的就是Blazor Server引入有關SignalR的js
第20行
<component type="typeof(App)" render-mode="ServerPrerendered" />
代表預設會注入一個叫做App的Component
~\BlazorServerApp1\App.razor
1 2 3 4 5 6 7 8 9 10 | <Router AppAssembly="@typeof(Program).Assembly" PreferExactMatches="@true"> <Found Context="routeData"> <RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" /> </Found> <NotFound> <LayoutView Layout="@typeof(MainLayout)"> <p>Sorry, there's nothing at this address.</p> </LayoutView> </NotFound> </Router> |
採用ServerPreRendered的模式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | #region 組件 Microsoft.AspNetCore.Mvc.ViewFeatures, Version=5.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60 // C:\Program Files\dotnet\packs\Microsoft.AspNetCore.App.Ref\5.0.0\ref\net5.0\Microsoft.AspNetCore.Mvc.ViewFeatures.dll #endregion namespace Microsoft.AspNetCore.Mvc.Rendering { // // 摘要: // Describes the render mode of the component. // // 備註: // The rendering mode determines how the component gets rendered on the page. It // configures whether the component is prerendered into the page or not and whether // it simply renders static HTML on the page or if it includes the necessary information // to bootstrap a Blazor application from the user agent. public enum RenderMode { // // 摘要: // Renders the component into static HTML. Static = 1, // // 摘要: // Renders a marker for a Blazor server-side application. This doesn't include any // output from the component. When the user-agent starts, it uses this marker to // bootstrap a blazor application. Server = 2, // // 摘要: // Renders the component into static HTML and includes a marker for a Blazor server-side // application. When the user-agent starts, it uses this marker to bootstrap a blazor // application. ServerPrerendered = 3, // // 摘要: // Renders a marker for a Blazor webassembly application. This doesn't include any // output from the component. When the user-agent starts, it uses this marker to // bootstrap a blazor client-side application. WebAssembly = 4, // // 摘要: // Renders the component into static HTML and includes a marker for a Blazor webassembly // application. When the user-agent starts, it uses this marker to bootstrap a blazor // client-side application. WebAssemblyPrerendered = 5 } } |
在App 元件又有引入了一些MainLayout元件
~\BlazorServerApp1\Shared\MainLayout.razor
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | @inherits LayoutComponentBase <div class="page"> <div class="sidebar"> <NavMenu /> </div> <div class="main"> <div class="top-row px-4"> <a href="https://docs.microsoft.com/aspnet/" target="_blank">About</a> </div> <div class="content px-4"> @Body </div> </div> </div> |
MainLayout元件裡面定義側欄Menu的元件
~\BlazorServerApp1\Shared\NavMenu.razor
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | <div class="top-row pl-4 navbar navbar-dark"> <a class="navbar-brand" href="">BlazorServerApp1</a> <button class="navbar-toggler" @onclick="ToggleNavMenu"> <span class="navbar-toggler-icon"></span> </button> </div> <div class="@NavMenuCssClass" @onclick="ToggleNavMenu"> <ul class="nav flex-column"> <li class="nav-item px-3"> <NavLink class="nav-link" href="" Match="NavLinkMatch.All"> <span class="oi oi-home" aria-hidden="true"></span> Home </NavLink> </li> <li class="nav-item px-3"> <NavLink class="nav-link" href="counter"> <span class="oi oi-plus" aria-hidden="true"></span> Counter </NavLink> </li> <li class="nav-item px-3"> <NavLink class="nav-link" href="fetchdata"> <span class="oi oi-list-rich" aria-hidden="true"></span> Fetch data </NavLink> </li> </ul> </div> @code { private bool collapseNavMenu = true; private string NavMenuCssClass => collapseNavMenu ? "collapse" : null; private void ToggleNavMenu() { collapseNavMenu = !collapseNavMenu; } } |
這裡每個<NavLink class="nav-link" href="xxxx"></NavLink>
也就是App.razor當中會傳遞的route資料,藉此來換頁。
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
留言
張貼留言