1. 前言
距離上次發《MAUI初體驗:爽》一文已經過去2個月了,本計劃是下半年或者明年再研究MAUI的,現在計劃提前啦,因為我覺得MAUI Blazor挺有意思的:在Android、iOS、macOS、Windows之間共享UI,一處UI增加或者修改,就能得到一致的UI體驗。
看看這篇文章《Blazor Hybrid/MAUI 簡介和實戰[1]》對MAUI Blazor的說明:
MAUI
.NET 多平臺應用程序 UI (.NET MAUI) 是一個跨平臺框架,用于使用 C# 和 XAML 創建本機移動和桌面應用程序, 使用 .net MAUI,可以開發可在 Android、iOS、macOS 上運行的應用,Windows 以及從單個共享代碼庫運行的應用。
Blazor Hybrid 應用和 .NET MAUI
Blazor Hybrid 支持內置于 .NET 多平臺應用 UI (.NET MAUI) 框架。.NET MAUI 包含 BlazorWebView 控件,該控件運行將 Razor 組件呈現到嵌入式 Web View 中。通過結合使用 .NET MAUI 和 Blazor,可以跨移動設備、桌面設備和 Web 重復使用一組 Web UI 組件。
今天就分享如何在Blazor Server、Blazor Wasm、MAUI Blazor之間共享UI的實驗,這一步完成,后面開發應用時就方便多了(只針對UI修改)。
2. 先來體驗下各端最終效果
Blazor Server:http://server.dotnet9.com/
Blazor Wasm:http://wasm.dotnet9.com/
MAUI(Android\Windows\macOS):https://github.com/dotnet9/Dotnet9/tree/develop/src/Dotnet9.MAUI(源碼自行編譯)
Windows桌面、Blazor Server(在線)、Blazor Wasm(在線)、Android效果
iOS、macOS桌面效果
MAUI各端未做發布文件體驗(需要做相應平臺的發布簽名等操作),大家可以按下面介紹的方法創建項目編譯體驗一下。
iOS和macOS效果感謝青城同學[2]提供的圖片素材,站長mbp安裝了最新的macOS,xCode也是最新的,可能因為預覽版macOS原因,xCode無法打開,間接影響了maui編譯?

3. 新建項目
關于MAUI的環境搭建可參考這篇文章《在MAUI中使用Masa Blazor》,本文不再介紹環境搭建,直接使用VS 2022最新預覽版項目模板創建項目。
3.1 創建Blazor Server項目:Dotnet9.Server

3.2 創建Blazor WebAssembly項目:Dotnet9.Wasm

3.3 創建MAUI Blazor項目:Dotnet9.MAUI

3.4 查找共同點
在3個項目的上一層目錄,打開PowerShell,輸入tree /f
查看詳細的目錄文件組織結構:
仔細查看三個模板項目文件結構,我們找出共同的文件查看:
文件夾?PATH?列表
卷序列號為?76F5-AF62
C:.
│??Dotnet9.sln
│
├─Dotnet9.MAUI
【1?這里省略數個文件】
│??│
│??├─Data
│??│??????WeatherForecast.cs
│??│??????WeatherForecastService.cs
│??│
│??├─Pages
│??│??????Counter.razor
│??│??????FetchData.razor
│??│??????Index.razor
【2?這里省略數個文件】
│??│
│??├─Shared
│??│??????MainLayout.razor
│??│??????MainLayout.razor.css
│??│??????NavMenu.razor
│??│??????NavMenu.razor.css
│??│??????SurveyPrompt.razor
【3?這里省略數個文件】
│
├─Dotnet9.Server
│??│??App.razor
【4?這里省略數個文件】
│??│
│??├─Data
│??│??????WeatherForecast.cs
│??│??????WeatherForecastService.cs
│??│
│??├─Pages
│??│??????Counter.razor
│??│??????Error.cshtml
│??│??????Error.cshtml.cs
│??│??????FetchData.razor
│??│??????Index.razor
│??│??????_Host.cshtml
│??│??????_Layout.cshtml
│??│
│??├─Properties
│??│??????launchSettings.json
│??│
│??├─Shared
│??│??????MainLayout.razor
│??│??????MainLayout.razor.css
│??│??????NavMenu.razor
│??│??????NavMenu.razor.css
│??│??????SurveyPrompt.razor
【5?這里省略數個文件】
│
└─Dotnet9.Wasm
【6?這里省略數個文件】│├─Pages│??????Counter.razor│??????FetchData.razor│??????Index.razor│├─Properties│??????launchSettings.json│├─Shared│??????MainLayout.razor│??????MainLayout.razor.css│??????NavMenu.razor│??????NavMenu.razor.css│??????SurveyPrompt.razor
【7?這里省略數個文件】
發現都有Data
目錄和Pages
目錄(其中Wasm項目沒有Data目錄,使用的示例類是直接寫在FetchData.razor
文件@code{}
中的),那把這部分文件直接提取到類庫中就可以了,那就做吧。
4. 提取UI到Razor類庫
創建Razor類庫:Dotnet9.WebApp

下面開始UI的提取

如上圖,將Dotnet9.MAUI
項目的Data
、Pages
、Shared
三個目錄外加Main.razor
文件剪切到Dotnet9.WebApp
項目中,然后修改剪切后相應文件的命名空間Dotnet9.MAUI[xxx]
為Dotnet9.WebApp[xxx]
,打開Dotnet9.WebApp
項目的_Import.razor
文件,參考Dotnet9.MAUI
項目的_Import.razor
文件部分命名空間,修改如下:
@using?System.Net.Http
@using?Microsoft.AspNetCore.Authorization
@using?Microsoft.AspNetCore.Components.Forms
@using?Microsoft.AspNetCore.Components.Routing
@using?Microsoft.AspNetCore.Components.Web
@using?Microsoft.AspNetCore.Components.Web.Virtualization
@using?Microsoft.JSInterop
@using?Dotnet9.WebApp
@using?Dotnet9.WebApp.Shared
上面部分命名空間可以刪除(未嘗試),編譯Dotnet9.WebApp
項目,檢查是否正確編譯。
5. 各端項目修改
5.1 MAUI項目
添加
Dotnet9.WebApp
項目引用Program.cs
中using Dotnet9.MAUI.Data;
改為using Dotnet9.WebApp.Data
刪除
Data
、Pages
、Shared
三個目錄外加Main.razor
文件,上一步是剪切的話這步省略修改
_Imports.razor
文件,主要是添加Dotnet9.WebApp
項目命名空間引用
@using?System.Net.Http
@using?Microsoft.AspNetCore.Components.Forms
@using?Microsoft.AspNetCore.Components.Routing
@using?Microsoft.AspNetCore.Components.Web
@using?Microsoft.AspNetCore.Components.Web.Virtualization
@using?Microsoft.JSInterop
@using?Dotnet9.MAUI
@using?Dotnet9.WebApp
@using?Dotnet9.WebApp.Shared
MauiProgram.cs
修改引用的命名空間:using Dotnet9.MAUI.Data;
=>using Dotnet9.WebApp.Data;
打開
MainPage.xaml
,對路由組件命名空間的引用修改
添加命名空間xmlns:webApp="clr-namespace:Dotnet9.WebApp;assembly=Dotnet9.WebApp"
,修改代碼如下:
修改前:
<RootComponent?Selector="#app"?ComponentType="{x:Type?local:Main}"?/>
修改后:
<RootComponent?Selector="#app"?ComponentType="{x:Type?webApp:Main}"?/>
修改完畢,編譯運行Dotnet9.MAUI
項目吧,接下來修改Dotnet9.Server
項目。
5.2 Blazor Server項目
添加
Dotnet9.WebApp
項目引用Program.cs
中using Dotnet9.Server.Data;
改為using Dotnet9.WebApp.Data;
刪除
Data
目錄刪除
Pages
目錄中的Counter.razor
、FetchData.razor
、Index.razor
三個文件(包括同名的.cs
、.css
文件)刪除
Shared
目錄修改
_Imports.razor
文件,主要是添加Dotnet9.WebApp
項目命名空間引用
@using?System.Net.Http
@using?Microsoft.AspNetCore.Authorization
@using?Microsoft.AspNetCore.Components.Authorization
@using?Microsoft.AspNetCore.Components.Forms
@using?Microsoft.AspNetCore.Components.Routing
@using?Microsoft.AspNetCore.Components.Web
@using?Microsoft.AspNetCore.Components.Web.Virtualization
@using?Microsoft.JSInterop
@using?Dotnet9.Server
@using?Dotnet9.WebApp
@using?Dotnet9.WebApp.Shared
打開
./Pages/_Host.cshtml
文件,添加命名空間引用@using Dotnet9.WebApp
,修改代碼如下:
修改前:
<component?type="typeof(App)"?render-mode="ServerPrerendered"?/>
修改后:
<component?type="typeof(Main)"?render-mode="ServerPrerendered"?/>
修改完畢,編譯運行Dotnet9.Server
項目吧,接下來修改Dotnet9.Wasm
項目。
5.3 Blazor Wasm項目
添加
Dotnet9.WebApp
項目引用刪除
Pages
、Shared
目錄外加App.razor
文件Program.cs
中using Dotnet9.Wasm;
改為using Dotnet9.WebApp;
,同時修改代碼
修改前
builder.RootComponents.Add<App>("#app");
修改后
builder.RootComponents.Add<Main>("#app");
修改
_Imports.razor
文件,主要是添加Dotnet9.WebApp
項目命名空間引用
@using?System.Net.Http
@using?Microsoft.AspNetCore.Authorization
@using?Microsoft.AspNetCore.Components.Authorization
@using?Microsoft.AspNetCore.Components.Forms
@using?Microsoft.AspNetCore.Components.Routing
@using?Microsoft.AspNetCore.Components.Web
@using?Microsoft.AspNetCore.Components.Web.Virtualization
@using?Microsoft.JSInterop
@using?Dotnet9.Server
@using?Dotnet9.WebApp
@using?Dotnet9.WebApp.Shared
修改完畢,編譯運行Dotnet9.Wasm
項目,至此三種項目模板已經修改完成,最終解決方案如下圖:

6 總結
總結就是下圖:

Dotnet9.WebApp:blazor組件相關的代碼、路由組件等放在這個工程,供其他項目引用
Dotnet9.Server:Blazor Server模板項目
Dotnet9.Wasm:Blazor WebAssembly項目
Dotnet9.MAUI:MAUI Blazor項目
一句話:將UI封裝到Razor類庫Dotnet9.WebApp
,其他終端工程(Dotnet9.Server
、Dotnet9.MAUI
、Dotnet9.Wasm
)引用此工程即可實現UI共享。
本文代碼地址:https://github.com/dotnet9/Dotnet9[3]
原文:https://dotnet9.com/2022/06/Share-razor-library-between-maui-and-blazor-server-or-client[4]
參考
ASP.NET Community Standup - Native client apps with Blazor Hybrid[5]
Blazor一份代碼在Blazor WebAssembly和Blazor Server之間任意切換[6]
微軟MAUI文檔[7]
微軟Blazor文檔[8]
學Blazor[9]
參考資料
[1]
Blazor Hybrid/MAUI 簡介和實戰: https://www.cnblogs.com/densen2014/p/16240966.html
[2]青城同學: https://iwscl.com/
[3]https://github.com/dotnet9/Dotnet9: https://github.com/dotnet9/Dotnet9
[4]https://dotnet9.com/2022/06/Share-razor-library-between-maui-and-blazor-server-or-client: https://dotnet9.com/2022/06/Share-razor-library-between-maui-and-blazor-server-or-client
[5]ASP.NET Community Standup - Native client apps with Blazor Hybrid: https://www.youtube.com/watch?v=7UM6s0QPvRQ
[6]Blazor一份代碼在Blazor WebAssembly和Blazor Server之間任意切換: https://www.bilibili.com/video/BV1ty4y137yA?spm_id_from=333.337.search-card.all.click&vd_source=fc9bd0ca1f113a165ad3ebf4fb79b124
[7]微軟MAUI文檔: https://docs.microsoft.com/zh-cn/dotnet/maui/?WT.mc_id=dotnet-35129-website
[8]微軟Blazor文檔: https://docs.microsoft.com/zh-cn/aspnet/core/blazor/?WT.mc_id=dotnet-35129-website&view=aspnetcore-6.0
[9]學Blazor: https://dotnet9.com/album/Let-us-learn-blazor-together