多個裝載的 ASP.NET Core Blazor WebAssembly 應用程式

注意

這不是這篇文章的最新版本。 如需本文的最新版本,請參閱 .NET 7 版本

本文說明如何設定裝載 Blazor WebAssembly 的應用程式來裝載多個 Blazor WebAssembly 應用程式。

組態

選取符合您裝載需求的本文版本、連接埠/網域裝載 (例如 :5001/:5002firstapp.com/secondapp.com) 或路由子路徑裝載 (例如 /FirstApp/SecondApp)。

使用目前的裝載選項,本文涵蓋連接埠/網域裝載 (例如 :5001/:5002firstapp.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.comsecondapp.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/App2Client1/Client21/2 或任何類似的命名配置。

當透過連接埠或網域將要求路由傳送至用戶端應用程式時,系統會在內部使用「FirstApp」和「SecondApp」來路由要求並提供靜態資產的回應,且不會顯示在瀏覽器的網址列中。

注意

本文中的示範會將靜態 Web 資產路徑名稱 FirstApp 用於 MultipleBlazorApps.Client 專案,而 SecondApp 用於 MultipleBlazorApps.SecondClient 專案。 名稱「FirstApp」和「SecondApp」只是為了示範目的。 其他可接受用來辨別用戶端應用程式的名稱,例如 App1/App2Client1/Client21/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.comsecondapp.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.HostRequireHost,可能會受到用戶端的詐騙。

    若要防止主機和連接埠詐騙,請使用下列其中一種方法:

  • 新增將要求對應至用戶端應用程式的中介軟體。 下列範例會設定當要求子路徑 /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 靜態檔案

如需 UseBlazorFrameworkFilesMapFallbackToFile 的詳細資訊,請參閱下列資源:

注意

.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]")]

如果您打算從伺服器應用程式提供頁面,請將 IndexRazor 頁面新增至伺服器應用程式的 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()
    {
        return View();
    }
}
using Microsoft.AspNetCore.Mvc;

namespace MultipleBlazorApps.Server.Controllers
{
    public class HomeController : Controller
    {
        public IActionResult Index()
        {
            return View();
        }
    }
}

注意

上述 Index 檢視只是為了示範目的而建立的最小範例。 如果應用程式需要額外的 MVC 資產,例如配置、樣式、指令碼和匯入,請從以 MVC 專案範本建立的應用程式取得這些資產。 如需詳細資訊,請參閱開始使用 ASP.NET Core MVC

如需在伺服器應用程式的頁面或檢視中使用用戶端應用程式 Razor 元件的詳細資訊,請參閱預先轉譯和整合 ASP.NET Core Razor 元件

執行應用程式

執行 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 run 命令 (.NET CLI) 執行應用程式時,請確認命令殼層已在方案的 Server 資料夾中開啟。

使用 Visual Studio 的 [開始] 按鈕執行應用程式時,請確認 MultipleBlazorApps.Server 專案已設定為啟始專案 (在 [方案總管] 中醒目提示)。

靜態資產

當資產位於用戶端應用程式的 wwwroot 資料夾中時,請在元件中提供靜態資產要求路徑:

<img alt="..." src="{PATH AND FILE NAME}" />

{PATH AND FILE NAME} 預留位置是 wwwroot 下的路徑和檔案名稱。

例如,wwwrootvehicle 資料夾中的 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" />

其他資源