多個裝載的 ASP.NET Core Blazor WebAssembly 應用程式
注意
這不是這篇文章的最新版本。 如需本文的最新版本,請參閱 .NET 7 版本。
本文說明如何設定裝載 Blazor WebAssembly 的應用程式來裝載多個 Blazor WebAssembly 應用程式。
組態
選取符合您裝載需求的本文版本、連接埠/網域裝載 (例如 :5001
/:5002
或 firstapp.com
/secondapp.com
) 或路由子路徑裝載 (例如 /FirstApp
和 /SecondApp
)。
使用目前的裝載選項,本文涵蓋連接埠/網域裝載 (例如 :5001
/:5002
或 firstapp.com
/secondapp.com
)。
在下列範例中:
- 裝載 Blazor WebAssembly 應用程式的專案名稱為
MultipleBlazorApps
,位於名為MultipleBlazorApps
的資料夾。 - 新增第二個用戶端應用程式之前,方案中的三個專案,
MultipleBlazorApps.Client
位於Client
資料夾、MultipleBlazorApps.Server
位於Server
資料夾,以及MultipleBlazorApps.Shared
位於Shared
資料夾中。 - 初始 (第一個) 用戶端應用程式是從 Blazor WebAssembly 專案範本所建立方案的預設用戶端專案。
- 第二個用戶端應用程式會新增至方案,
MultipleBlazorApps.SecondClient
位於名為SecondClient
的資料夾中。 - 選擇性地,伺服器專案 (
MultipleBlazorApps.Server
) 可以提供頁面或檢視作為 Razor Pages 或 MVC 應用程式。 - 第一個用戶端應用程式可在連接埠 5001 的瀏覽器中或使用
firstapp.com
的主機來存取。 第二個用戶端應用程式可在連接埠 5002 的瀏覽器中或使用secondapp.com
的主機來存取。
使用目前的選取範圍,本文涵蓋路由子路徑裝載 (例如 /FirstApp
和 /SecondApp
)。
在下列範例中:
- 裝載 Blazor WebAssembly 應用程式的專案名稱為
MultipleBlazorApps
,位於名為MultipleBlazorApps
的資料夾。 - 新增第二個用戶端應用程式之前,方案中的三個專案,
MultipleBlazorApps.Client
位於Client
資料夾、MultipleBlazorApps.Server
位於Server
資料夾,以及MultipleBlazorApps.Shared
位於Shared
資料夾中。 - 初始 (第一個) 用戶端應用程式是從 Blazor WebAssembly 專案範本所建立方案的預設用戶端專案。
- 第二個用戶端應用程式會新增至方案,
MultipleBlazorApps.SecondClient
位於名為SecondClient
的資料夾中。 - 選擇性地,伺服器專案 (
MultipleBlazorApps.Server
) 可以提供頁面或檢視作為正式的 Razor Pages 或 MVC 應用程式。 - 這兩個用戶端應用程式都會使用
MultipleBlazorApps.Server
專案的Properties/launchSettings.json
檔案在其applicationUrl
值中定義的預設連接埠。 第一個用戶端應用程式可在/FirstApp
子路徑的瀏覽器中存取。 第二個用戶端應用程式可在/SecondApp
子路徑的瀏覽器中存取。
本文所示的範例需要額外的設定才能:
- 直接在範例主機網域
firstapp.com
和secondapp.com
存取應用程式。 - 用戶端應用程式用來啟用 TLS/HTTPS 安全性的憑證。
- 將伺服器應用程式設定為 Razor Pages 應用程式以獲得下列功能:
- 將 Razor 元件整合至頁面或檢視中。
- 預先呈現 Razor 元件。
上述設定超出本文的範圍。 如需詳細資訊,請參閱以下資源:
如果使用 .NET CLI,或在 IDE 中建立專案時選取 Visual Studio 中的 [裝載的ASP.NET Core] 核取方塊,請使用現有裝載 Blazor WebAssembly 的方案,或透過傳遞 -ho|--hosted
選項,從 Blazor WebAssembly 專案範本建立新裝載 Blazor WebAssembly 的方案。
針對名為 MultipleBlazorApps
的方案使用資料夾,並將專案命名為 MultipleBlazorApps
。
在名為 SecondClient
的方案中建立新資料夾。 在新資料夾中,新增名為 MultipleBlazorApps.SecondClient
的第二個 Blazor WebAssembly 用戶端應用程式。 將專案新增為獨立 Blazor WebAssembly 應用程式。 若要建立獨立 Blazor WebAssembly 應用程式,如果使用 .NET CLI,請勿傳遞 -ho|--hosted
選項,或者如果使用 Visual Studio,請勿使用 [裝載的 ASP.NET Core] 核取方塊。
對 MultipleBlazorApps.SecondClient
專案進行下列變更:
- 將
FetchData
元件 (Pages/FetchData.razor
) 從Client/Pages
資料夾複製到SecondClient/Pages
資料夾。 這是必要步驟,因為獨立 Blazor WebAssembly 應用程式不會呼叫 Server 專案的天氣資料控制器,而會使用靜態資料檔案。 藉由將FetchData
元件複製到新增的專案,第二個用戶端應用程式也會針對天氣資料對伺服器 API 進行 Web API 呼叫。 - 刪除
SecondClient/wwwroot/sample-data
資料夾,因為資料夾中的weather.json
檔案未使用。
下表描述新增 SecondClient
資料夾和 MultipleBlazorApps.SecondClient
專案之後,方案的資料夾和專案名稱。
實體資料夾 | 專案名稱 | 描述 |
---|---|---|
Client |
MultipleBlazorApps.Client |
Blazor WebAssembly 用戶端應用程式 |
SecondClient |
MultipleBlazorApps.SecondClient |
Blazor WebAssembly 用戶端應用程式 |
Server |
MultipleBlazorApps.Server |
ASP.NET Core 伺服器應用程式 |
Shared |
MultipleBlazorApps.Shared |
共用資源專案 |
此 MultipleBlazorApps.Server
專案提供兩個 Blazor WebAssembly 用戶端應用程式,並透過 MVC 控制器將天氣資料提供給用戶端應用程式的 FetchData
元件。 或者,MultipleBlazorApps.Server
專案也可以以傳統 Razor Pages 或 MVC 應用程式的形式提供頁面或檢視。 本文稍後會討論啟用提供頁面或檢視的步驟。
注意
本文中的示範會將靜態 Web 資產路徑名稱 FirstApp
用於 MultipleBlazorApps.Client
專案,而 SecondApp
用於 MultipleBlazorApps.SecondClient
專案。 名稱「FirstApp
」和「SecondApp
」只是為了示範目的。 其他可接受用來辨別用戶端應用程式的名稱,例如 App1
/App2
、Client1
/Client2
、1
/2
或任何類似的命名配置。
當透過連接埠或網域將要求路由傳送至用戶端應用程式時,系統會在內部使用「FirstApp
」和「SecondApp
」來路由要求並提供靜態資產的回應,且不會顯示在瀏覽器的網址列中。
注意
本文中的示範會將靜態 Web 資產路徑名稱 FirstApp
用於 MultipleBlazorApps.Client
專案,而 SecondApp
用於 MultipleBlazorApps.SecondClient
專案。 名稱「FirstApp
」和「SecondApp
」只是為了示範目的。 其他可接受用來辨別用戶端應用程式的名稱,例如 App1
/App2
、Client1
/Client2
、1
/2
或任何類似的命名配置。
「FirstApp
」和「SecondApp
」也會出現在瀏覽器的網址列中,因為系統會使用這些名稱將要求路由傳送至兩個用戶端應用程式。 支援其他有效的 URL 路由區段,且路由區段不需要完全符合用來在內部路由靜態 Web 資產的名稱。 針對內部靜態資產路由和應用程式要求路由使用「FirstApp
」和「SecondApp
」只是為了本文範例中的慣例。
在第一個用戶端應用程式的專案檔 (MultipleBlazorApps.Client.csproj
) 中,將 <StaticWebAssetBasePath>
屬性 新增至 <PropertyGroup>
,而其值為 FirstApp
,以設定專案靜態資產的基底路徑:
<StaticWebAssetBasePath>FirstApp</StaticWebAssetBasePath>
在 MultipleBlazorApps.SecondClient
應用程式的專案檔 (MultipleBlazorApps.SecondClient.csproj
) 中:
將
<StaticWebAssetBasePath>
屬性新增至<PropertyGroup>
,而其值為SecondApp
:<StaticWebAssetBasePath>SecondApp</StaticWebAssetBasePath>
將
MultipleBlazorApps.Shared
專案的專案參考新增至<ItemGroup>
:<ItemGroup> <ProjectReference Include="..\Shared\MultipleBlazorApps.Shared.csproj" /> </ItemGroup>
在伺服器應用程式的專案檔 (Server/MultipleBlazorApps.Server.csproj
) 中,為 <ItemGroup>
中新增的 MultipleBlazorApps.SecondClient
用戶端應用程式建立專案參考:
<ProjectReference Include="..\SecondClient\MultipleBlazorApps.SecondClient.csproj" />
在伺服器應用程式的 Properties/launchSettings.json
檔案中,將 Kestrel 設定檔 (MultipleBlazorApps.Server
) 的 applicationUrl
設定為在連接埠 5001 和 5002 存取用戶端應用程式。 如果您將本機環境設定為使用範例網域,則 applicationUrl
的 URL 可以使用 firstapp.com
和 secondapp.com
,且不使用連接埠。
注意
此示範中的連接埠使用可讓您存取本機瀏覽器中的用戶端專案,而不需要設定本機裝載環境,讓網頁瀏覽器可以透過主機設定 firstapp.com
以及 secondapp.com
存取用戶端應用程式。 在生產案例中,一般設定是使用子網域來區分用戶端應用程式。
例如:
- 連接埠會從此示範的設定卸除。
- 主機會變更為使用子網域,例如
www.contoso.com
用於網站訪客,而admin.contoso.com
用於系統管理員。 - 其他用戶端應用程式可以包含其他主機,如果伺服器應用程式也是提供頁面或檢視的 Razor Pages 或 MVC 應用程式,則至少需要一個主機。
如果您打算從伺服器應用程式提供頁面或檢視,請在 Properties/launchSettings.json
檔案中使用下列 applicationUrl
設定,以允許下列存取:
- 或者,Razor Pages 或 MVC 應用程式 (
MultipleBlazorApps.Server
專案) 會在連接埠 5000 回應要求。 - 對第一個用戶端 (
MultipleBlazorApps.Client
專案) 的要求回應位於連接埠 5001。 - 對第二個用戶端 (
MultipleBlazorApps.SecondClient
專案) 的要求回應位於連接埠 5002。
"applicationUrl": "https://localhost:5000;https://localhost:5001;https://localhost:5002",
如果您不打算讓伺服器應用程式提供頁面或檢視,而只提供 Blazor WebAssembly 用戶端應用程式,請使用下列設定,以允許下列存取:
- 第一個用戶端應用程式會在連接埠 5001 回應。
- 第二個用戶端應用程式會在連接埠 5002 回應。
"applicationUrl": "https://localhost:5001;https://localhost:5002",
在伺服器應用程式的 Program.cs
檔案中,移除下列會出現在對 UseHttpsRedirection 呼叫之後的程式碼:
如果您打算從伺服器應用程式提供頁面或檢視,請刪除下列幾行程式碼:
- app.UseBlazorFrameworkFiles();
- app.MapFallbackToFile("index.html");
如果您打算讓伺服器應用程式只提供 Blazor WebAssembly 用戶端應用程式,請刪除下列程式碼:
- app.UseBlazorFrameworkFiles(); ... - app.UseRouting(); - app.MapRazorPages(); - app.MapControllers(); - app.MapFallbackToFile("index.html");
就地保留靜態檔案中介軟體:
app.UseStaticFiles();
新增將要求對應至用戶端應用程式的中介軟體。 下列範例會將中介軟體設定為當要求連接埠為 5001 用於第一個用戶端應用程式或 5002 用於第二個用戶端應用程式時,或要求主機為第一個用戶端應用程式的
firstapp.com
或第二個用戶端應用程式的secondapp.com
時執行。注意
在本機系統上搭配本機瀏覽器使用主機 (
firstapp.com
/secondapp.com
) 需要超出本文範圍的其他設定。 針對此案例的本機測試,我們建議使用連接埠。 一般生產應用程式會設定為使用子網域,例如www.contoso.com
用於網站訪客,而admin.contoso.com
用於系統管理員。 使用適當的 DNS 和伺服器設定超出本文的範圍,並取決於所使用的技術,應用程式會在下列程式碼中命名任何主機時回應要求。當您從
Program.cs
中移除app.UseBlazorFrameworkFiles();
行時,請放置下列程式碼:app.MapWhen(ctx => ctx.Request.Host.Port == 5001 || ctx.Request.Host.Equals("firstapp.com"), first => { first.Use((ctx, nxt) => { ctx.Request.Path = "/FirstApp" + ctx.Request.Path; return nxt(); }); first.UseBlazorFrameworkFiles("/FirstApp"); first.UseStaticFiles(); first.UseStaticFiles("/FirstApp"); first.UseRouting(); first.UseEndpoints(endpoints => { endpoints.MapControllers(); endpoints.MapFallbackToFile("/FirstApp/{*path:nonfile}", "FirstApp/index.html"); }); }); app.MapWhen(ctx => ctx.Request.Host.Port == 5002 || ctx.Request.Host.Equals("secondapp.com"), second => { second.Use((ctx, nxt) => { ctx.Request.Path = "/SecondApp" + ctx.Request.Path; return nxt(); }); second.UseBlazorFrameworkFiles("/SecondApp"); second.UseStaticFiles(); second.UseStaticFiles("/SecondApp"); second.UseRouting(); second.UseEndpoints(endpoints => { endpoints.MapControllers(); endpoints.MapFallbackToFile("/SecondApp/{*path:nonfile}", "SecondApp/index.html"); }); });
警告
依賴於主機標頭的 API (例如 HttpRequest.Host 和 RequireHost) 可能會受到用戶端的詐騙。
若要防止主機和連接埠詐騙,請使用下列其中一種方式:
- 使用可在其中檢查連接埠的 HttpContext.Connection (ConnectionInfo.LocalPort)。
- 採用主機篩選。
新增將要求對應至用戶端應用程式的中介軟體。 下列範例會設定當要求子路徑
/FirstApp
用於第一個用戶端應用程式,或/SecondApp
用於第二個用戶端應用程式時,要執行的中介軟體。當您從
Program.cs
中移除app.UseBlazorFrameworkFiles();
行時,請放置下列程式碼:app.MapWhen(ctx => ctx.Request.Path.StartsWithSegments("/FirstApp", StringComparison.OrdinalIgnoreCase), first => { first.UseBlazorFrameworkFiles("/FirstApp"); first.UseStaticFiles(); first.UseStaticFiles("/FirstApp"); first.UseRouting(); first.UseEndpoints(endpoints => { endpoints.MapControllers(); endpoints.MapFallbackToFile("/FirstApp/{*path:nonfile}", "FirstApp/index.html"); }); }); app.MapWhen(ctx => ctx.Request.Path.StartsWithSegments("/SecondApp", StringComparison.OrdinalIgnoreCase), second => { second.UseBlazorFrameworkFiles("/SecondApp"); second.UseStaticFiles(); second.UseStaticFiles("/SecondApp"); second.UseRouting(); second.UseEndpoints(endpoints => { endpoints.MapControllers(); endpoints.MapFallbackToFile("/SecondApp/{*path:nonfile}", "SecondApp/index.html"); }); });
在每個用戶端應用程式中設定基底路徑:
在第一個用戶端應用程式的
index.html
檔案 (Client/wwwroot/index.html
) 中,更新<base>
標籤值以反映子路徑。 需要後置斜線:<base href="/FirstApp/" />
在第二個用戶端應用程式的
index.html
檔案 (SecondClient/wwwroot/index.html
) 中,更新<base>
標籤值以反映子路徑。 需要後置斜線:<base href="/SecondApp/" />
如需 UseStaticFiles 的詳細資訊,請參閱 ASP.NET Core Blazor 靜態檔案。
如需 UseBlazorFrameworkFiles
和 MapFallbackToFile
的詳細資訊,請參閱下列資源:
- Microsoft.AspNetCore.Builder.ComponentsWebAssemblyApplicationBuilderExtensions.UseBlazorFrameworkFiles (參考來源)
- Microsoft.AspNetCore.Builder.StaticFilesEndpointRouteBuilderExtensions.MapFallbackToFile (參考來源)
注意
.NET 參考來源的文件連結通常會載入存放庫的預設分支,這表示下一版 .NET 的目前開發。 若要選取特定版本的標籤,請使用 [切換分支或標籤] 下拉式清單。 如需詳細資訊,請參閱如何選取 ASP.NET Core 原始程式碼 (dotnet/AspNetCore.Docs #26205) 的版本標籤。
從用戶端應用程式到伺服器 API 中 /WeatherForecast
的要求是 /FirstApp/WeatherForecast
或 /SecondApp/WeatherForecast
取決於用戶端應用程式提出要求。 因此,從伺服器 API 傳回天氣資料的控制器路由需要修改才能包含路徑區段。
在伺服器應用程式的氣象預報控制器 (Controllers/WeatherForecastController.cs
) 中,將現有對 WeatherForecastController
的路由 ([Route("[controller]")]
) 取代為下列路由,以考慮用戶端要求路徑:
[Route("FirstApp/[controller]")]
[Route("SecondApp/[controller]")]
如果您打算從伺服器應用程式提供頁面,請將 Index
Razor 頁面新增至伺服器應用程式的 Pages
資料夾:
Pages/Index.cshtml
:
@page
@model MultipleBlazorApps.Server.Pages.IndexModel
@{
ViewData["Title"] = "Home";
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Home</title>
</head>
<body>
<div class="main">
<div class="content px-4">
<div>
<h1>Welcome</h1>
<p>Hello from Razor Pages!</p>
</div>
</div>
</div>
</body>
</html>
Pages/Index.cshtml.cs
:
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace MultipleBlazorApps.Server.Pages;
public class IndexModel : PageModel
{
public void OnGet()
{
}
}
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace MultipleBlazorApps.Server.Pages
{
public class IndexModel : PageModel
{
public void OnGet()
{
}
}
}
注意
上述 Index
頁面只是為了示範目的而建立的最小範例。 如果應用程式需要其他 Razor Pages 資產,例如版面配置、樣式、指令碼和匯入,請從以 Razor Pages 專案範本建立的應用程式取得這些資產。 如需詳細資訊,請參閱 ASP.NET Core 中的 Razor Pages 簡介。
如果您打算從伺服器應用程式提供 MVC 檢視,請新增 Index
檢視和 Home
控制器:
Views/Home/Index.cshtml
:
@{
ViewData["Title"] = "Home";
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Home</title>
</head>
<body>
<div class="main">
<div class="content px-4">
<div>
<h1>Welcome</h1>
<p>Hello from MVC!</p>
</div>
</div>
</div>
</body>
</html>
Controllers/HomeController.cs
:
using Microsoft.AspNetCore.Mvc;
namespace MultipleBlazorApps.Server.Controllers;
public class HomeController : Controller
{
public IActionResult Index() => View();
}
注意
上述 Index
檢視只是為了示範目的而建立的最小範例。 如果應用程式需要額外的 MVC 資產,例如配置、樣式、指令碼和匯入,請從以 MVC 專案範本建立的應用程式取得這些資產。 如需詳細資訊,請參閱開始使用 ASP.NET Core MVC。
如需在Razor頁面或伺服器應用程式檢視中使用用戶端應用程式元件的詳細資訊,請參閱在託管Blazor WebAssembly解決方案中整合 ASP.NET Core Razor 元件與 MVC 或 Razor Pages。
執行應用程式
執行 MultipleBlazorApps.Server
專案:
- 在
https://localhost:5001
存取初始用戶端應用程式。 - 在
https://localhost:5002
存取新增的用戶端應用程式。 - 如果伺服器應用程式設定為提供頁面或檢視,請在
https://localhost:5000
存取Index
頁面或檢視。
- 在
https://localhost:{DEFAULT PORT}/FirstApp
存取初始用戶端應用程式。 - 在
https://localhost:{DEFAULT PORT}/SecondApp
存取新增的用戶端應用程式。 - 如果伺服器應用程式設定為提供頁面或檢視,請在
https://localhost:{DEFAULT PORT}
存取Index
頁面或檢視。
在上述範例 URL 中,{DEFAULT PORT}
預留位置是 MultipleBlazorApps.Server
專案的 Properties/launchSettings.json
檔案在其 applicationUrl
值中定義的預設連接埠。
重要
使用 dotnet watch
(或 dotnet run
) 命令 (.NET CLI) 執行應用程式時,請確認命令殼層已在解決方案的 Server
資料夾中開啟。
使用 Visual Studio 的 [開始] 按鈕執行應用程式時,請確認 MultipleBlazorApps.Server
專案已設定為啟始專案 (在 [方案總管] 中醒目提示)。
靜態資產
當資產位於用戶端應用程式的 wwwroot
資料夾中時,請在元件中提供靜態資產要求路徑:
<img alt="..." src="{PATH AND FILE NAME}" />
{PATH AND FILE NAME}
預留位置是 wwwroot
下的路徑和檔案名稱。
例如,wwwroot
的 vehicle
資料夾中的 Jeep 影像 (jeep-yj.png
) 來源:
<img alt="Jeep Wrangler YJ" src="vehicle/jeep-yj.png" />
Razor 類別庫 (RCL) 支援
將 Razor 類別庫 (RCL) 新增至方案作為新專案:
- 以滑鼠右鍵按一下 [方案總管] 中的方案,然後選取 [加入]>[新增專案]。
- 使用 Razor 類別庫專案範本來建立專案。 本節中的範例會使用專案名稱
ComponentLibrary
,這也是 RCL 的組件名稱。 請勿選取 [支援頁面和檢視] 核取方塊。
針對每個裝載的 Blazor WebAssembly 用戶端應用程式,以滑鼠右鍵按一下 [方案總管] 中的每個用戶端專案,然後選取 [新增]>[專案參考],以建立 RCL 專案的專案參考。
在用戶端應用程式中使用來自 RCL 的元件,並搭配下列其中一種方法:
將
@using
指示詞放在 RCL 命名空間的元件頂端,並新增元件的 Razor 語法。 下列範例適用於元件名稱為ComponentLibrary
的 RCL:@using ComponentLibrary ... <Component1 />
提供 RCL 的命名空間以及元件的 Razor 語法。 此方法不需要元件檔案頂端的
@using
指示詞。 下列範例適用於元件名稱為ComponentLibrary
的 RCL:<ComponentLibrary.Component1 />
注意
@using
指示詞也可以放入每個用戶端應用程式的 _Import.razor
檔案中,讓 RCL 的命名空間可供該專案中的元件全域使用。
當任何其他靜態資產位於 RCL 的 wwwroot
資料夾中時,請根據具有 ASP.NET Core 之類別庫中可重複使用Razor UI 中的指導,參考用戶端應用程式中的靜態資產:
<img alt="..." src="_content/{PACKAGE ID}/{PATH AND FILE NAME}" />
{PACKAGE ID}
預留位置是 RCL 的套件識別碼。 如果未在專案檔中指定 <PackageId>
,則封裝識別碼預設為專案的組件名稱。 {PATH AND FILE NAME}
預留位置是 wwwroot
下的路徑和檔案名稱。
下列範例顯示 RCL wwwroot
資料夾之 vehicle
資料夾中 Jeep 影像 (jeep-yj.png
) 的標記。 下列範例適用於元件名稱為 ComponentLibrary
的 RCL:
<img alt="Jeep Wrangler YJ" src="_content/ComponentLibrary/vehicle/jeep-yj.png" />