瀏覽器中的 .Net Core —— Blazor WebAssembly 初體驗

前言

       在兩年多之前就聽聞 Blazor 框架,是 .Net 之父的業餘實驗性項目,其目的是探索 .Net 與 WebAssembly 的兼容性和應用前景。如今這個項目已經正式成爲 Asp.Net Core 框架的一部分,公開了預覽版,官方教程也基本寫好上線了。就着這個機會,順便體驗一下這個框架用起來如何。html

       以前在網上搜索 Blazor 的相關信息的時候發現吵得很厲害。前端開發者大多以爲有 Vue 之類的前端 MVVM 框架已經夠用,沒有 C# 插足的餘地。甚至不少 C# 開發者也不知道這個框架的基本工做原理,以爲是把 C# 翻譯成 js,翻譯以後就變成了相似 Vue 的東西。還有人以爲這是下一個 Flash 或者 Silverlight。毛主席曾經說過:沒有調查就沒有發言權。對於說這種話的人,我只想說,少刷幾分鐘抖音快手隨便搜下百度都能搞清楚怎麼回事,做爲 C# 開發者,這都理解不了我是真不知道是怎麼學的 C#,難道真是傳說中的拖控件一把梭,而後就沒而後了?前端

       簡單說明下 Blazor WebAssembly 的工做原理。就是在 WebAssembly 框架的基礎上,實現了一個 .Net Core Runtime,用一個啓動 js 下載相關 dll、初始化 .Net 虛擬機、啓動虛擬機運行入口函數,接下來就和一個正常 .Net 程序同樣,該怎麼運行怎麼運行。用 Java 的說法就是在瀏覽器中運行的 jvm。今後,.Net 跨平臺領先 Java 一步,除了 Windows、Linux、MacOS以外,還要加上瀏覽器。悄悄說一下,瀏覽器上的運行時實現了 netstandard 2.1,待遇比傳統的 .Net Framework 還好。要說缺點就是調試很麻煩,由於整個運行過程和服務器無關,在 VS 下斷點也沒用,不知道是預覽版沒作好仍是什麼緣由,順便致使出問題很難跟蹤。還有改了代碼要從新編譯項目,不能像 MVC 那樣改了 cshtml 刷新下瀏覽器就生效。每次重啓調試太耐等了。git

正文

       目前 Blazor WebAssembly 還不是默認項目模板的一部分,須要自行下載模板才能在 VS 2019 的項目模板裏找到,須要的能夠移步官方教程。不知道有多少園友知道我有個專門收集各類各類我以爲有趣的示例代碼的項目,固然也有不少代碼是我本身寫的。我就冒出了一個想法,如何把這個項目也集成到個人現有項目中。畢竟建立獨立的項目和在現有項目中融合新東西徹底是兩種感受,不少組件一旦融合就會各類衝突打架,須要深刻了解他們才能知道衝突有沒有辦法解決,要如何解決。github

       通過幾天的研究,我成功把 Blazor WebAssembly 項目融合進了個人主項目。同時進行了一些改造。主要方法仍是先新建一個模板項目,而後對比代碼差別,融合代碼,補充 nuget 包。接下來簡要說明下在現有 Asp.Net Core 項目中增長 Blazor WebAssembly 項目的主要步驟。在個人項目中,/blazor 是 Blazor 根目錄,各類修改都配合這個設定,各位請根據本身的狀況修改。api

客戶端

       一、新建一個包含 Asp.Net Core 宿主服務器的 Blazor WebAssembly 項目。純 Blazor WebAssembly 項目發佈後能夠放到靜態文件服務器,宿主服務器也只是當文件服務器用。把客戶端項目複製到主項目解決方案中,在 VS 中添加現有項目。若是修改過項目名稱和命名空間,請重啓 VS,否則可能報錯。瀏覽器

       二、複製共享項目到主項目的解決方案,修復項目引用。安全

       三、修改 wwwroot/index.html,修改 <head> 標籤中的 <base href="/" /> 爲 <base href="/blazor" />。服務器

       四、在 wwwroot 文件夾新建文件夾 blazor,把 wwwroot 下的其餘文件和文件夾放進 wwwroot/blazor 文件夾,避免和主項目路徑衝突,一樣地,主項目也不能再用 /blazor/xxx 了。網絡

服務端

       一、安裝 nuget 包 Microsoft.AspNetCore.Blazor.Server,要勾上包括預發行版,否則搜不到。mvc

       二、在主項目中引用客戶端項目和共享項目。

       三、在 Startup.ConfigureServices 中增長代碼:

1 services.AddResponseCompression(opts =>
2 {
3     opts.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(
4         new[] { "application/octet-stream" });
5 });

       四、在 Startup.Configure 中增長 app.UseBlazorDebugging(); 若是隻想在開發環境使用,自行增長 if 判斷。通常跟 app.UseDeveloperExceptionPage(); 放在一塊兒。

       五、在 Startup.Configure 中註冊 Blazor 文件,注意類型參數,是客戶端項目的 Program 類:

app.UseClientSideBlazorFiles<BlazorApp.Client.Program>();

       六、在 Startup.Configure 中檢查是否有並補充 app.UseStaticFiles();

       七、在 Startup.Configure 中註冊路由終結點,注意 "/blazor/{**subPath}" 這一段,表示把 blazor 映射到 /blazor/xxx 去。{**subPath} 這一段是路由終結點參數捕獲語法,裏面的 subPath 能夠亂寫,但不能空着不填,否則啓動不了。由於 Blazor WebAssembly 啓動以後路由都是前端完成的,跟服務器沒有任何關係,因此能夠亂填。只是要知足系統的語法要求好讓服務器能正常啓動。

1 app.UseEndpoints(endpoints =>
2 {
3     //之前的 mvc、api 等等各類註冊。
4 
5     //映射 Blazor 客戶端終結點
6     endpoints.MapFallbackToClientSideBlazor<BlazorApp.Client.Program>("/blazor/{**subPath}", "index.html");
7 });

       至此,融合工做完成,能夠正常啓動項目並訪問 /blazor 體驗效果了。

效果預覽

在兩個瀏覽器(Chrome、Edge by Chromium)分別登陸不一樣帳號,分別使用 Blazor WebAssembly SignalR .Net Core Client 和 SignalR Javascript Client 鏈接 SignalR 服務,手機(Edge Android)再登陸另外一個帳號使用 Blazor WebAssembly SignalR .Net Core Client 鏈接 SignalR 服務(域名是花生殼域名作 DDNS)。實現跨平臺跨終端實時聊天。運行在 Release 發佈模式。

 

 結語

       整體來講,Blazor 的體驗仍是很不錯的,總體風格和 Asp.Net Core 幾乎一摸同樣,我看見的一瞬間就感受很是親切。依賴注入系統也能夠正常使用,只是區別是 Scope 生命週期的實際效果和單例是同樣的,由於整個應用就只有一個 Scope,可是 Blazor Server Side 就有區別了,每一個 SignalR 鏈接綁定一個 Scope,掉線重連成功也會恢復到原先的 Scope ,一直連不上過久就不行了,整個服務器進程包含一個單例。因此在註冊的時候儘可能用 Scope,避免單例成習慣,緩不過來。

       Razor 語法也是個神同樣的設計,最初是做爲 MVC3 的視圖引擎推出,在 MVC4 成爲默認引擎。好像 MVC5 取消了 aspx 視圖引擎支持,.Net Core 完全取消了和 aspx 有關的一切東西。如今,Razor 又成爲了一個前端渲染框架,真是老樹發新芽,又是一春。在 html 模板渲染上,我用下來就是 Razor 的 @ 和 Vue 的雙花括號語法特別順手,aspx 那種尖括號語法實在看的頭昏腦脹。原本 html 就各類尖括號,還要再來一堆尖括號,VS 高亮都看得頭疼,更別說通常文本編輯器打開了,根本看不懂,到底誰和誰是一對?Razor 就特別爽,代碼和標記自動識別切換,局部代碼塊,局部變量,比起 Vue 是有過之而無不及(Vue 的變量做用域師從 js,是真的暈)。

       根據目前使用的狀況來看,只要不包含涉及系統底層調用的庫均可以正常使用,好比和進程、線程、硬件驅動相關、本機 dll 互操做這種。

       我在模板項目中,增長了 SignalR 客戶端使用示例。也是根據官方教程修改,並且使用的客戶端庫就是普通 .Net 客戶端庫,和控制檯、桌面程序用是同一套 dll。微軟果真神,究竟是怎麼把網絡相關的 API 底層實現神不知鬼不覺地的換掉的。默認注入的 HttpClient 也是 System.Net.Http 命名空間的。

       因爲網絡通訊底層其實是依賴瀏覽器,因此瀏覽器會自動把 HttpClient 的請求嫁接到瀏覽器上,相關的 Headers、Cookies 天然也會自動攜帶上。因此若是 Blazor 應用和普通網頁在同一個域,這些東西實際上會共享。個人身份認證相關功能就是利用這個特色偷懶實現的。若是不在同一個域,最簡單實用的方法就是用 IdentityServer4 做爲認證服務,客戶端引用 nuget 包 IdentityModel,這個包會給 HttpClient 增長一堆用來和 OpenId Connect、OAuth2.0 協議交互的擴展方法,看成兩個程序用開放協議配合工做來寫就行。用 IdentityModel 擴展獲取 Access Token,請求的時候把 Token 加進 HttpClient 的 Headers,固然也能夠用 IdentityModel 的擴展來注入,更方便。

       對於 SPA 應用來講,狀態管理必定是沒法繞過的,不過在 Blazor 中,直接用依賴注入來管理狀態就能夠了。若是須要刷新頁面也不丟失狀態的話,能夠考慮使用 ILocalStorage 服務來持久化狀態,或者其餘持久化方案也行,反正支持 js 互操做,先隨便封裝一個應急,等 C# 的原生組件出來了再看怎麼辦。

       與服務器的交互除了常規的 Web Api,還有內部預覽階段的 gRPC-Web,等這東西搞定了,Blazor 極限使用一切二進制數據,那效率不知道能提高多少。Asp.Net Core 3.0 全面支持 HTTP2,Chrome 好像從 70 日後也都支持 HTTP2,gRPC-Web 原生使用 HTTP2 確定比如今包一層兼容層支持 HTTP1.1 來的好。能夠說在瀏覽器的限制下,能作的應該都差很少。不知道之後瀏覽器會不會開放線程接口讓 WebAssembly 使用內核線程執行計算密集型任務(好像會更方便黑客把瀏覽器當礦機啊,開放的問題也是多的不行,感受瀏覽器就是個黑暗森林,網站服務器要防用戶搞破壞,用戶也要防網站用腳本搞破壞,這個猜疑鏈也致使瀏覽器各類限制,難啊)。

        做爲一個雜食性開發者,對於 Blazor 與 Vue 的爭論這種東西我是無所謂的,只要在個人知識範圍內在我能接受的開發複雜度內解決問題,其餘的都是浮雲。就像鄧爺爺說的:實踐是檢驗真理的惟一標準;管他黑貓白貓,抓到耗子就是好貓;這纔是個人信條,完全的實用主義。

       啊,C# 這種強類型安全語言進入前端領域有點激動,不注意就說了一大通。被 js 那詭異的對象類型,動態做用域坑的實在是不行,敲鍵盤的時候心虛不知道會不會莫名其妙忽然就出問題,實在是對心臟很差。仍是喜歡 C#,什麼東西都清晰明瞭,不埋暗坑,外加 DLR 和 dynamic,真是進可攻、退可守。js 徹底沒有退路,實在是傷不起。

       在最後發佈之後才發現 Blazor 聊天進不去,調試正常,試了N多辦法都沒搞定,最後刪除發佈文件夾中的全部 dll,關閉 VS,刪除 obj、bin 文件夾,從新發布才正常。真是坑爹。

 

       轉載請完整保留如下內容並在顯眼位置標註,未經受權刪除如下內容進行轉載盜用的,保留追究法律責任的權利!

  本文地址:http://www.javashuo.com/article/p-hqftgsla-bp.html

  完整源代碼:Github

  裏面有各類小東西,這只是其中之一,不嫌棄的話能夠Star一下。

相關文章
相關標籤/搜索