1. 前言
距離上次發《MAUI 初體驗:爽》一文已經過去 2 個月了,本計劃是下半年或者明年再研究 MAUI 的,現在計劃提前啦,因為我覺得 MAUI Blazor 滿有意思的:在 Android、iOS、macOS、Windows 之間共用 UI,一處 UI 增加或者修改,就能得到一致的 UI 體驗。
看看這篇文章《Blazor Hybrid/MAUI 簡介和實戰》對 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:https://server.dotnet9.com/
- Blazor Wasm:https://wasm.dotnet9.com/
- MAUI(Android\Windows\macOS):https://github.com/dotnet9/Dotnet9/tree/develop/src/Dotnet9.MAUI(原始碼自行編譯)
Windows 桌面、Blazor Server(線上)、Blazor Wasm(線上)、Android 效果

iPad Air、iOS、macOS 桌面效果

MAUI 各端未做發佈檔案體驗(需要做相應平台的發佈簽署等操作),大家可以按下面介紹的方法建立專案編譯體驗一下。
iOS 和 macOS 效果感謝青城同學提供的圖片素材,站長 mbp 安裝了最新的 macOS,xCode 也是最新的,可能是因為預覽版 macOS 原因,xCode 無法開啟,間接影響了 maui 編譯?
macOS 版本和 xCode 版本

xCode 為不可用狀態

VS 編譯錯誤,之後再解決

用 mbp 的同學建議不要安裝預覽版作業系統,不要當勇士....
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
- 刪除
App.razor檔案,開啟./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
- 原文:https://dotnet9.com/2022/06/Share-razor-library-between-maui-and-blazor-server-or-client
參考