ASP.NET Core Blazor 轉譯模式

本文說明在編譯時間或執行階段,Blazor Web 應用程式中的 Razor 元件轉譯控制項。

本指導不適用獨立 Blazor WebAssembly 應用程式。 Blazor WebAssembly 應用程式只會透過用戶端 WebAssembly 型執行階段在用戶端上轉譯,而且沒有轉譯模式的概念。 如果將轉譯模式套用至 Blazor WebAssembly 應用程式中的元件,則轉譯模式指定不會影響元件的轉譯。

轉譯模式

Blazor Web 應用程式中的每個元件都會採用轉譯模式來判斷其所使用的裝載模型、轉譯的位置,以及其是否為互動式。

下表顯示 Blazor Web 應用程式中轉譯 Razor 元件的可用轉譯模式。 若要將轉譯模式套用至元件,請使用元件執行個體或元件定義上的 @rendermode 指示詞。 本文稍後會針對每個轉譯模式案例顯示範例。

名稱 描述 轉譯位置 互動式
靜態伺服器 靜態伺服器端轉譯 (靜態 SSR) 伺服器
互動式伺服器 使用 Blazor Server 的互動式伺服器端轉譯 (互動式 SSR)。 伺服器
互動式 WebAssembly 使用 Blazor WebAssembly 的用戶端轉譯 (CSR)†。 Client
互動式自動 一開始使用 Blazor Server 進行互動式 SSR,然後在下載 Blazor 套件組合之後,於後續造訪時使用 CSR。 伺服器,然後用戶端

† 用戶端轉譯 (CSR) 會假設為互動式。 產業或 Blazor 文件中不會使用「互動式用戶端轉譯」和「互動式 CSR」。

互動式元件預設會啟用預先轉譯功能。 本文稍後會提供控制預先轉譯的指導。 如需用戶端和伺服器轉譯概念的一般產業術語,請參閱 ASP.NET Core Blazor 基本概念

下列範例會示範使用一些基本 Razor 元件功能來設定元件的轉譯模式。

若要在本機測試轉譯模式行為,您可以將下列元件放在從 Blazor Web 應用程式專案範本建立的應用程式中。 當您建立應用程式時,請從下拉式功能表選取選項 (Visual Studio) 或套用 CLI 選項 (.NET CLI),以啟用伺服器端和用戶端互動功能。 如需如何建立 Blazor Web 應用程式的指導,請參閱 ASP.NET Core Blazor 的工具

啟用互動式轉譯模式的支援

Blazor Web 應用程式必須設定為支援互動式轉譯模式。 下列延伸模組會自動套用至在應用程式建立期間從 BlazorWeb 應用程式專案範本建立的應用程式。 在應用程式 Program 檔案中設定元件服務和端點之後,每個轉譯模式區段仍需要個別元件宣告其轉譯模式。

呼叫 AddRazorComponents 以新增 Razor 元件的服務。

元件建立器延伸模組:

MapRazorComponents 會探索可用的元件,並指定應用程式的根元件 (載入的第一個元件),其預設為 App 元件 (App.razor)。

端點慣例建立器延伸模組:

注意

如需在下列範例中放置 API 的方向,請檢查從 Blazor Web 應用程式專案範本產生的應用程式 Program 檔案。 如需如何建立 Blazor Web 應用程式的指導,請參閱 ASP.NET Core Blazor 的工具

範例 1:下列 Program 檔案 API 會新增服務和設定,以啟用互動式 SSR:

builder.Services.AddRazorComponents()
    .AddInteractiveServerComponents();
app.MapRazorComponents<App>()
    .AddInteractiveServerRenderMode();

範例 2:下列 Program 檔案 API 會新增服務和設定,以啟用互動式 WebAssembly 轉譯模式:

builder.Services.AddRazorComponents()
    .AddInteractiveWebAssemblyComponents();
app.MapRazorComponents<App>()
    .AddInteractiveWebAssemblyRenderMode();

範例 3:下列 Program 檔案 API 會新增服務和設定,以啟用互動式伺服器、互動式 WebAssembly 和互動式自動轉譯模式:

builder.Services.AddRazorComponents()
    .AddInteractiveServerComponents()
    .AddInteractiveWebAssemblyComponents();
app.MapRazorComponents<App>()
    .AddInteractiveServerRenderMode()
    .AddInteractiveWebAssemblyRenderMode();

Blazor 會使用 Blazor WebAssembly 主控模型下載並執行使用互動式 WebAssembly 轉譯模式的元件。 需要個別的用戶端專案,才能設定這些元件的 Blazor WebAssembly 裝載。 用戶端專案包含 Blazor WebAssembly 主機的啟動程式碼,並設定 .NET 執行階段以在瀏覽器中執行。 當您選取啟用 WebAssembly 互動的選項時,Blazor Web 應用程式範本會為您新增此用戶端專案。 應該從用戶端專案建置任何使用互動式 WebAssembly 轉譯模式的元件,使其包含在下載的應用程式套件組合中。

將轉譯模式套用至元件執行個體

若要將轉譯模式套用至元件執行個體,請在使用元件的位置使用 @rendermodeRazor 指示詞屬性

在下列範例中,互動式伺服器端轉譯 (互動式 SSR) 會套用至 Dialog 元件執行個體:

<Dialog @rendermode="InteractiveServer" />

注意

Blazor 範本在應用程式的 _Imports 檔案 (Components/_Imports.razor) 中包含 RenderMode 的靜態 using 指示詞,以取得較短的 @rendermode 語法:

@using static Microsoft.AspNetCore.Components.Web.RenderMode

如果沒有上述指示詞,元件必須以 @rendermode 語法指定靜態 RenderMode 類別:

<Dialog @rendermode="RenderMode.InteractiveServer" />

您也可以參考使用自訂設定直接具現化的自訂轉譯模式執行個體。 如需詳細資訊,請參閱本文稍後的自訂速記轉譯模式一節。

將轉譯模式套用至元件定義

若要指定元件轉譯模式做為其定義的一部分,請使用 @rendermodeRazor 指示詞和對應的轉譯模式屬性。

@page "..."
@rendermode InteractiveServer

將轉譯模式套用至元件定義,通常會在將轉譯模式套用至特定頁面時使用。 路由頁面預設會使用與轉譯頁面的 Router 元件相同的轉譯模式。

在技術上,@rendermode 既是 Razor指示詞,也是 Razor指示詞屬性。 語意類似,但有差異。 @rendermode 指示詞位於元件定義上,因此參考的轉譯模式執行個體必須為靜態。 @rendermode 指示詞屬性可以採用任何轉譯模式執行個體。

注意

元件作者應避免將元件的實作與特定轉譯模式結合。 相反地,元件作者通常應該設計元件,使其能夠支援任何轉譯模式或裝載模型。 元件實作應該避免假設其執行的位置 (伺服器或用戶端),而且在靜態轉譯時應該正常降級。 如果未直接具現化元件,或指定所有元件執行個體的轉譯模式,則可能需要在元件定義中指定轉譯模式。例如,使用可路由的頁面元件來指定轉譯模式。

將轉譯模式套用至整個應用程式

若要設定整個應用程式的轉譯模式,請指出應用程式元件階層中最高層級互動式元件的轉譯模式,且該元件不是根元件。

注意

不支援讓根元件成為互動式,例如 App 元件。 因此,整個應用程式的轉譯模式無法由 App 元件直接設定。

針對以 Blazor Web 應用程式專案範本為基礎的應用程式,指派給整個應用程式的轉譯模式通常會在 App 元件 (Components/App.razor) 中使用 Routes 元件所在的位置指定:

<Routes @rendermode="InteractiveServer" />

Router 元件會將其轉譯模式傳播至其路由的頁面。

您通常也必須在 HeadOutlet 元件上設定相同的互動式轉譯模式,該元件也能在從專案範本產生的 Blazor Web 應用程式 App 元件中找到:

<HeadOutlet @rendermode="InteractiveServer" />

針對採用互動式用戶端 (WebAssembly 或自動) 轉譯模式,並透過 Routes 元件啟用整個應用程式轉譯模式的應用程式:

  • 將伺服器應用程式 Components/Layout 資料夾的配置和瀏覽檔案放置或移至 .Client 專案的 Layout 資料夾。 在 .Client 專案中建立 Layout 資料夾 (如不存在)。
  • 將伺服器應用程式 Components/Pages 資料夾的元件放置或移至 .Client 專案的 Pages 資料夾。 在 .Client 專案中建立 Pages 資料夾 (如不存在)。
  • 將伺服器應用程式 Routes 資料夾的 Components 元件放置或移至 .Client 專案的根資料夾。

若要在建立 Blazor Web 應用程式時啟用全域互動功能:

  • Visual Studio:將 [互動位置] 下拉式清單設定為 [全域]
  • .NET CLI:使用 -ai|--all-interactive 選項。

如需詳細資訊,請參閱 ASP.NET Core Blazor 工具。

以程式設計方式套用轉譯模式

屬性和欄位可以指派轉譯模式。

本節所述的第二個方法,依元件執行個體設定轉譯模式,在您的應用程式規格符合下列任一案例時特別有用:

  • 您有一個應用程式的區域 (資料夾) 具有必須採用靜態伺服器端轉譯 (靜態 SSR),且只能在伺服器上執行的元件。 應用程式會根據資料夾的路徑,在 App 元件中的 Routes 元件上設定轉譯模式,以全域控制轉譯模式。
  • 您在各種位置 (不在單一資料夾中) 有圍繞應用程式的元件,其必須採用靜態 SSR,而且只能在伺服器上執行。 應用程式會在元件執行個體中使用 @rendermode 指示詞來設定轉譯模式,以每一元件為基礎控制轉譯模式。 在 App 元件中使用反映,以在 Routes 元件上設定轉譯模式。

在這兩個情況下,必須採用靜態 SSR 的元件也必須強制全頁重新載入。

上述兩個案例涵蓋本文稍後的轉譯模式精細控制小節中的範例。 下列兩個子節著重於設定轉譯模式的基本方法。

依元件定義設定轉譯模式

元件定義可以透過私人欄位定義轉譯模式:

@rendermode renderModeForPage

...

@code {
    private static IComponentRenderMode renderModeForPage = InteractiveServer;
}

依元件執行個體設定轉譯模式

下列範例會將互動式伺服器端轉譯 (互動式 SSR) 套用至任何要求。

<Routes @rendermode="RenderModeForPage" />

...

@code {
    private IComponentRenderMode? RenderModeForPage => InteractiveServer;
}

本文稍後的轉譯模式傳播一節會提供轉譯模式傳播的其他資訊。 轉譯模式的精細控制一節示範如何使用上述方法,在應用程式的特定區域 (資料夾) 中或針對具有每一元件轉譯模式指派的圍繞應用程式散佈的特定元件採用靜態 SSR。

預先轉譯

預先轉譯是伺服器上初始轉譯頁面內容,而不需要為轉譯的控制項啟用事件處理常式的程序。 伺服器會盡快輸出頁面的 HTML UI,以回應初始要求,如此可改善應用程式對使用者的回應速度。 預先轉譯也可改善搜尋引擎最佳化 (SEO),方法是轉譯搜尋引擎用來計算頁面排名的初始 HTTP 回應的內容。

互動式元件預設會啟用預先轉譯功能。

若要停用元件執行個體的預先轉譯,請傳遞具有 false 值的 prerender 旗標至轉譯模式:

  • <... @rendermode="new InteractiveServerRenderMode(prerender: false)" />
  • <... @rendermode="new InteractiveWebAssemblyRenderMode(prerender: false)" />
  • <... @rendermode="new InteractiveAutoRenderMode(prerender: false)" />

若要停用元件定義中的預先轉譯:

  • @rendermode @(new InteractiveServerRenderMode(prerender: false))
  • @rendermode @(new InteractiveWebAssemblyRenderMode(prerender: false))
  • @rendermode @(new InteractiveAutoRenderMode(prerender: false))

若要停用整個應用程式的預先轉譯,請指出應用程式元件階層中最高層級互動式元件的轉譯模式,且該元件不是根元件。

針對以 Blazor Web 應用程式專案範本為基礎的應用程式,指派給整個應用程式的轉譯模式會在 App 元件 (Components/App.razor) 中使用 Routes 元件所在的位置指定。 下列範例會將應用程式的轉譯模式設定為停用預先轉譯的互動式伺服器:

<Routes @rendermode="new InteractiveServerRenderMode(prerender: false)" />

此外,請停用 App 元件中 HeadOutlet 元件的預先轉譯:

<HeadOutlet @rendermode="new InteractiveServerRenderMode(prerender: false)" />

不支援讓根元件 (例如 @rendermode 元件) 與根元件定義檔 (.razor) 上的 App 指示詞互動。 因此,App 元件無法直接停用預先轉譯。

靜態伺服器端轉譯 (靜態 SSR)

元件會預設使用靜態伺服器端轉譯 (靜態 SSR)。 元件會轉譯至回應資料流程,且未啟用互動功能。

在下列範例中,元件轉譯模式沒有指定,因此元件會從其父代繼承其轉譯模式。 由於沒有上階元件指定轉譯模式,下列元件會在伺服器上靜態轉譯。 按鈕不是互動式的,而且不會在選取時呼叫 UpdateMessage 方法。 message 的值不會變更,而且元件不會在回應 UI 事件時重新轉譯。

RenderMode1.razor

@page "/render-mode-1"

<button @onclick="UpdateMessage">Click me</button> @message

@code {
    private string message = "Not updated yet.";

    private void UpdateMessage()
    {
        message = "Somebody updated me!";
    }
}

如果在本機 Blazor Web 應用程式中使用上述元件,請將元件放在伺服器專案的 Components/Pages 資料夾中。 伺服器專案是解決方案的專案,且其名稱不會以 .Client 結尾。 當應用程式執行時,在瀏覽器網址列中瀏覽至 /render-mode-1

在靜態 SSR 期間,Razor 元件頁面要求會由伺服器端 ASP.NET Core 中介軟體管線處理,要求針對路由和授權處理。 路由和授權的專用 Blazor 功能無法運作,因為 Razor 元件不會在伺服器端要求處理期間轉譯。 在靜態 SSR 期間無法使用的 Routes 元件中的 Blazor 路由器功能包括顯示:

如果應用程式表現出根層級互動功能,在初始靜態 SSR 之後未涉及伺服器端 ASP.NET Core 要求處理,則表示上述 Blazor 功能如預期般運作。

使用靜態 SSR 的增強式瀏覽載入 JavaScript 時需要特別注意。 如需詳細資訊,請參閱 ASP.NET Core Blazor JavaScript 搭配靜態伺服器端轉譯 (靜態 SSR)

互動式伺服器端轉譯 (互動式 SSR)

互動式伺服器端轉譯 (互動式SSR) 會使用 Blazor Server,以互動方式從伺服器轉譯元件。 使用者互動是透過瀏覽器的即時連線來處理。 轉譯伺服器元件時會建立線路連線。

在下列範例中,透過新增 @rendermode InteractiveServer 至元件定義,將轉譯模式設定為互動式 SSR。 按鈕會在選取時呼叫 UpdateMessage 方法。 message 的值會變更,而且元件會重新轉譯以更新 UI 中的訊息。

RenderMode2.razor

@page "/render-mode-2"
@rendermode InteractiveServer

<button @onclick="UpdateMessage">Click me</button> @message

@code {
    private string message = "Not updated yet.";

    private void UpdateMessage()
    {
        message = "Somebody updated me!";
    }
}

如果在本機 Blazor Web 應用程式中使用上述元件,請將元件放在伺服器專案的 Components/Pages 資料夾中。 伺服器專案是解決方案的專案,且其名稱不會以 .Client 結尾。 當應用程式執行時,在瀏覽器網址列中瀏覽至 /render-mode-2

用戶端轉譯 (CSR)

用戶端轉譯 (CSR) 會使用 Blazor WebAssembly 以互動方式在用戶端上轉譯元件。 一開始轉譯 WebAssembly 元件時,會下載並快取 .NET 執行階段和應用程式套件組合。 使用 CSR 的元件,必須從設定 Blazor WebAssembly 主機的個別用戶端專案建置。

在下列範例中,轉譯模式會使用 @rendermode InteractiveWebAssembly 設定為 CSR。 按鈕會在選取時呼叫 UpdateMessage 方法。 message 的值會變更,而且元件會重新轉譯以更新 UI 中的訊息。

RenderMode3.razor

@page "/render-mode-3"
@rendermode InteractiveWebAssembly

<button @onclick="UpdateMessage">Click me</button> @message

@code {
    private string message = "Not updated yet.";

    private void UpdateMessage()
    {
        message = "Somebody updated me!";
    }
}

如果在本機 Blazor Web 應用程式中使用上述元件,請將元件放在用戶端專案的 Pages 資料夾中。 用戶端專案是方案的專案,且其名稱以 .Client 結尾。 當應用程式執行時,在瀏覽器網址列中瀏覽至 /render-mode-3

自動 (自動) 轉譯

自動 (自動) 轉譯會決定如何在執行階段轉譯元件。 元件一開始會使用 Blazor Server 主控模型,以互動式伺服器端轉譯 (互動式 SSR) 來轉譯。 .NET 執行階段和應用程式套件組合會在背景下載到用戶端並快取,以便在未來造訪時使用。

自動轉譯模式絕不會動態變更頁面上已存在元件的轉譯模式。 自動轉譯模式會針對要用於元件的互動功能類型做出初始決策,只要該互動功能類型位於頁面上,該元件就會保留該類型的互動功能。 此初始決策的其中一個因素是要考量網頁上的元件是否存在 WebAssembly/伺服器互動功能。 自動模式偏好選取符合現有互動式元件的轉譯模式。 自動模式偏好使用現有互動功能模式的原因是要避免引入未與現有執行階段共用狀態的新互動式執行階段。

使用自動轉譯模式的元件,必須從設定 Blazor WebAssembly 主機的個別用戶端專案建置。

在下列範例中,元件在整個流程中都為互動式。 按鈕會在選取時呼叫 UpdateMessage 方法。 message 的值會變更,而且元件會重新轉譯以更新 UI 中的訊息。 一開始,元件會以互動方式從伺服器轉譯,但在後續造訪時,元件會在下載並快取 .NET 執行階段和應用程式套件組合之後,從用戶端轉譯。

RenderMode4.razor

@page "/render-mode-4"
@rendermode InteractiveAuto

<button @onclick="UpdateMessage">Click me</button> @message

@code {
    private string message = "Not updated yet.";

    private void UpdateMessage()
    {
        message = "Somebody updated me!";
    }
}

如果在本機 Blazor Web 應用程式中使用上述元件,請將元件放在用戶端專案的 Pages 資料夾中。 用戶端專案是方案的專案,且其名稱以 .Client 結尾。 當應用程式執行時,在瀏覽器網址列中瀏覽至 /render-mode-4

轉譯模式傳播

轉譯模式會向下傳播元件階層。

套用轉譯模式的規則:

  • 預設轉譯模式為靜態。
  • 互動式伺服器 (InteractiveServer)、互動式 WebAssembly (InteractiveWebAssembly) 和互動式自動 (InteractiveAuto) 轉譯模式可從元件使用,包括針對同層級元件使用不同的轉譯模式。
  • 您無法切換至子系元件中的不同互動式轉譯模式。 例如,伺服器元件不能是 WebAssembly 元件的子系。
  • 從靜態父代傳遞至互動式子系元件的參數必須為 JSON 可序列化。 這表示您無法將轉譯片段或子系內容從靜態父代元件傳遞至互動式子系元件。

下列範例使用非可路由傳送的非頁面 SharedMessage 元件。 與轉譯模式無關 SharedMessage 元件不會套用具有 @attribute 指示詞的轉譯模式。 如果您要使用 Blazor Web 應用程式測試這些案例,請將下列元件放在應用程式的 Components 資料夾中。

SharedMessage.razor

<p>@Greeting</p>

<button @onclick="UpdateMessage">Click me</button> @message

<p>@ChildContent</p>

@code {
    private string message = "Not updated yet.";

    [Parameter]
    public RenderFragment? ChildContent { get; set; }

    [Parameter]
    public string Greeting { get; set; } = "Hello!";

    private void UpdateMessage()
    {
        message = "Somebody updated me!";
    }
}

轉譯模式繼承

如果 SharedMessage 元件放在靜態轉譯的父代元件中,則 SharedMessage 元件也會以靜態方式而非互動式轉譯。 按鈕不會呼叫 UpdateMessage,而且不會更新訊息。

RenderMode5.razor

@page "/render-mode-5"

<SharedMessage />

如果 SharedMessage 元件放在定義轉譯模式的元件中,則會繼承套用的轉譯模式。

在下列範例中,SharedMessage 元件透過 SignalR 與用戶端的連線為互動式。 按鈕會呼叫 UpdateMessage,並更新訊息。

RenderMode6.razor

@page "/render-mode-6"
@rendermode InteractiveServer

<SharedMessage />

具有不同轉譯模式的子系元件

在下列範例中,這兩個 SharedMessage 元件都已 (依預設) 預先轉譯,而且會在瀏覽器中顯示頁面時顯示。

  • 建立 SignalR 線路之後,具有互動式伺服器端轉譯 (互動式 SSR) 的第一個 SharedMessage 元件為互動式。
  • 具有用戶端轉譯 (CSR) 的第二個 SharedMessage 元件在下載 Blazor 應用程式套件組合之後且 .NET 執行階段在用戶端上為使用中時為互動式。

RenderMode7.razor

@page "/render-mode-7"

<SharedMessage @rendermode="InteractiveServer" />
<SharedMessage @rendermode="InteractiveWebAssembly" />

具有可序列化參數的子系元件

下列範例示範採用參數的互動式子系元件。 參數必須可序列化。

RenderMode8.razor

@page "/render-mode-8"

<SharedMessage @rendermode="InteractiveServer" Greeting="Welcome!" />

支援不可序列化的元件參數,例如子系內容或轉譯片段。 在下列範例中,將子系內容傳遞至 SharedMessage 元件會導致執行階段錯誤。

RenderMode9.razor

@page "/render-mode-9"

<SharedMessage @rendermode="InteractiveServer">
    Child content
</SharedMessage>

錯誤:

System.InvalidOperationException:無法使用轉譯模式 'InteractiveServerRenderMode' 將參數 'ChildContent' 傳遞至元件 'SharedMessage'。 這是因為參數委派類型為 'Microsoft.AspNetCore.Components.RenderFragment',這是任意程式碼且無法序列化。

若要規避上述限制,請將子系元件包裝在另一個沒有參數的元件中。 這是使用 Routes 元件 (Components/Routes.razor) 包裝 Router 元件的 Blazor Web 應用程式專案範本中採用的方法。

WrapperComponent.razor

<SharedMessage>
    Child content
</SharedMessage>

RenderMode10.razor

@page "/render-mode-10"

<WrapperComponent @rendermode="InteractiveServer" />

在前述範例中:

  • 子系內容會傳遞至 SharedMessage 元件,而不會產生執行階段錯誤。
  • SharedMessage 元件會在伺服器上以互動方式轉譯。

具有與其父代不同轉譯模式的子系元件

請勿嘗試將與其父代轉譯模式不同的互動式轉譯模式套用至子系元件。

下列元件會在轉譯元件時產生執行階段錯誤:

RenderMode11.razor

@page "/render-mode-11"
@rendermode InteractiveServer

<SharedMessage @rendermode="InteractiveWebAssembly" />

錯誤:

Cannot create a component of type 'BlazorSample.Components.SharedMessage' because its render mode 'Microsoft.AspNetCore.Components.Web.InteractiveWebAssemblyRenderMode' is not supported by Interactive Server rendering.

對轉譯模式的精細控制

在某些情況下,應用程式的規格會要求元件採用靜態伺服器端轉譯 (靜態 SSR),並且只在伺服器上執行,而應用程式的其餘部分則使用互動式轉譯模式。

有兩個方法可以用於精細控制轉譯模式,下列子節中說明每個方法:

  • 靜態 SSR 元件的區域 (資料夾):您應用程式的一個區域 (資料夾) 具有的元件必須採用靜態 SSR,並共用相同的路由路徑前置詞。 應用程式會根據資料夾的路徑,在 App 元件中的 Routes 元件上設定轉譯模式,以全域控制轉譯模式。

  • 散佈在應用程式上的靜態 SSR 元件:您在各種位置有圍繞應用程式散佈的元件,其必須採用靜態 SSR,而且只能在伺服器上執行。 僅限靜態 SSR 元件不在單一資料夾中,而且不會共用共同的路由路徑前置詞。 應用程式會在元件執行個體中使用 @rendermode 指示詞來設定轉譯模式,以每一元件為基礎控制轉譯模式。 在 App 元件中使用反映,以在 Routes 元件上設定轉譯模式。

在這兩個情況下,必須採用靜態 SSR 的元件也必須強制全頁重新載入。

下列範例會使用 HttpContext 串聯參數來判斷頁面是否為靜態轉譯。 nullHttpContext 表示元件是以互動方式轉譯,這在應用程式程式碼中用來作為觸發完整頁面重新載入的訊號很有用。

靜態 SSR 元件的區域 (資料夾)

Blazor Web 應用程式專案範本會使用此子節中所述的方法,並搭配個別驗證和全域互動功能。

應用程式的區域 (資料夾) 包含必須採用靜態 SSR 且只在伺服器上執行的元件。 資料夾中的元件會共用相同的路由路徑前置詞。 例如,Blazor Web 應用程式專案範本的 IdentityRazor 元件位於 Components/Account/Pages 資料夾中,並共用根路徑前置詞 /Account

資料夾也包含 _Imports.razor 檔案,它會將自訂帳戶配置套用至資料夾中的元件:

@using BlazorSample.Components.Account.Shared
@layout AccountLayout

Shared 資料夾會維護 AccountLayout 配置元件。 元件會使用 HttpContext 來判斷元件是否在伺服器上轉譯。 Identity 元件必須在伺服器上使用靜態 SSR 轉譯,因為它們會設定 Identitycookie。 如果 HttpContext 的值是 null,元件會以互動方式轉譯,而完整頁面重新載入會藉由將 forceLoad 設定為 true 呼叫 NavigationManager.Refresh 來執行。 這會強制使用靜態 SSR 對頁面進行完整的重新轉譯。

Components/Account/Shared/AccountLayout.razor

@inherits LayoutComponentBase
@layout BlazorSample.Components.Layout.MainLayout
@inject NavigationManager NavigationManager

@if (HttpContext is null)
{
    <p>Loading...</p>
}
else
{
    @Body
}

@code {
    [CascadingParameter]
    private HttpContext? HttpContext { get; set; }

    protected override void OnParametersSet()
    {
        if (HttpContext is null)
        {
            NavigationManager.Refresh(forceReload: true);
        }
    }
}

注意

在 Blazor Web 應用程式專案範本中,Components/Account/Pages/Manage 資料夾中的 Identity 元件會有第二個配置檔案 (Components/Account/Shared 資料夾中的 ManageLayout.razor)。 Manage 資料夾有自己的 _Imports.razor 檔案,可套用至資料夾中元件的 ManageLayout。 在您自己的應用程式中,使用巢狀 _Imports.razor 檔案是將自訂配置套用至頁面群組的實用方法。

App 元件中,對 Account 資料夾中元件的任何要求都會套用 null 轉譯模式,其會強制執行靜態 SSR。 其他元件要求會接收互動式 SSR 轉譯模式 (InteractiveServer) 的全域應用程式。

重要

套用 null 轉譯模式不一定會強制執行靜態 SSR。 使用本節所示的方法,就是會以此方式運作。

null 轉譯模式實際上與未指定轉譯模式相同,這會導致元件繼承其父系的轉譯模式。 在此情況下,App 元件會使用靜態 SSR 轉譯,因此 null 轉譯模式會導致 Routes 元件從 App 元件繼承靜態 SSR。 如果為父代使用互動式轉譯模式的子元件指定 Null 轉譯模式,則子系會繼承相同的互動式轉譯模式。

Components/App.razor

<Routes @rendermode="RenderModeForPage" />

...

@code {
    [CascadingParameter]
    private HttpContext HttpContext { get; set; } = default!;

    private IComponentRenderMode? RenderModeForPage => 
        HttpContext.Request.Path.StartsWithSegments("/Account")
            ? null
            : {INTERACTIVE RENDER MODE};
}

在上述程式碼中,將 {INTERACTIVE RENDER MODE} 預留位置變更為適當的值,視應用程式的其餘部分是否應該採用全域 InteractiveServerInteractiveWebAssemblyInteractiveAuto 轉譯而定。

Account 資料夾中必須採用靜態 SSR 的元件不需要設定配置,因為它會透過 _Imports.razor 檔案套用,而且元件不會設定轉譯模式,因為它們應該使用靜態 SSR 轉譯。 Account 資料夾中的元件不需要再執行任何動作,即可強制執行靜態 SSR。

分散在應用程式上的靜態 SSR 元件

上述子節中,應用程式會藉由在 App 元件中全域設定轉譯模式,以控制元件的轉譯模式。 或者,App 元件也可以採用每一元件轉譯模式來設定轉譯模式,允許元件圍繞應用程式散佈,以強制採用靜態 SSR。 此子節描述方法。

應用程式具有自訂配置,可套用至圍繞應用程式的元件。 通常,應用程式的共用元件會放在 Components/Layout 資料夾中。 元件會使用 HttpContext 來判斷元件是否在伺服器上轉譯。 如果 HttpContext 的值是 null,元件會以互動方式轉譯,而完整頁面重新載入會藉由將 forceLoad 設定為 true 呼叫 NavigationManager.Refresh 來執行。 這會觸發對元件伺服器的要求。

Components/Layout/StaticSsrLayout.razor

@inherits LayoutComponentBase
@layout MainLayout
@inject NavigationManager NavigationManager

@if (HttpContext is null)
{
    <p>Loading...</p>
}
else
{
    @Body
}

@code {
    [CascadingParameter]
    private HttpContext? HttpContext { get; set; }

    protected override void OnParametersSet()
    {
        if (HttpContext is null)
        {
            NavigationManager.Refresh(forceReload: true);
        }
    }
}

App 元件中,反映是用來設定轉譯模式。 任何指派給個別元件定義檔的轉譯模式都會套用至 Routes 元件。

Components/App.razor

<Routes @rendermode="RenderModeForPage" />

...

@code {
    [CascadingParameter]
    private HttpContext HttpContext { get; set; } = default!;

    private IComponentRenderMode? RenderModeForPage =>
        HttpContext.GetEndpoint()?.Metadata.GetMetadata<RenderModeAttribute>()?
            .Mode;
}

每個必須採用靜態 SSR 的元件都會設定自訂配置,且指定轉譯模式。 未指定轉譯模式會導致 App 元件中 RenderModeAttribute.Modenull 值,這會導致未將轉譯模式指派給 Routes 元件執行個體,並強制執行靜態 SSR。

重要

套用 null 轉譯模式不一定會強制執行靜態 SSR。 使用本節所示的方法,就是會以此方式運作。

null 轉譯模式實際上與未指定轉譯模式相同,這會導致元件繼承其父系的轉譯模式。 在此情況下,App 元件會使用靜態 SSR 轉譯,因此 null 轉譯模式會導致 Routes 元件從 App 元件繼承靜態 SSR。 如果為父代使用互動式轉譯模式的子元件指定 Null 轉譯模式,則子系會繼承相同的互動式轉譯模式。

除了套用自訂配置而未設定互動式轉譯模式,元件不需要再執行任何動作,即可強制執行靜態 SSR:

@layout BlazorSample.Components.Layout.StaticSsrLayout

圍繞應用程式的互動式元件可避免套用自訂靜態 SSR 配置,且只會設定適當的互動式轉譯模式,其在 App 元件反映時會套用至 Routes 元件:

@rendermode {INTERACTIVE RENDER MODE}

在上述程式碼中,將 {INTERACTIVE RENDER MODE} 預留位置變更為適當的值,視元件是否應該採用 InteractiveServerInteractiveWebAssemblyInteractiveAuto 轉譯而定。

用戶端服務無法在預先轉譯期間解析

假設元件或應用程式未停用預先轉譯,則 .Client 專案中的元件會在伺服器上預先轉譯。 由於伺服器無法存取已註冊的用戶端 Blazor 服務,因此無法將這些服務插入元件,而不會在預先轉譯期間收到找不到服務的錯誤。

例如,在具有全域互動式 WebAssembly 或互動式自動轉譯的 Blazor Web 應用程式中,請考量 .Client 專案中的下列 Home 元件。 元件會嘗試插入 IWebAssemblyHostEnvironment 以取得環境的名稱。

@page "/"
@inject IWebAssemblyHostEnvironment Environment

<PageTitle>Home</PageTitle>

<h1>Home</h1>

<p>
    Environment: @Environment.Environment
</p>

未發生編譯時間錯誤,但在預先轉譯期間發生執行階段錯誤:

無法在類型 'BlazorSample.Client.Pages.Home' 上提供屬性 'Environment' 的值。 沒有類型 'Microsoft.AspNetCore.Components.WebAssembly.Hosting.IWebAssemblyHostEnvironment' 的已註冊服務。

之所以發生此錯誤,是因為元件必須在預先轉譯期間在伺服器上編譯和執行,但 IWebAssemblyHostEnvironment 不是伺服器上已註冊的服務。

如果應用程式在預先轉譯期間未要求值,可以藉由插入 IServiceProvider 來取得服務,而不是服務類型本身來解決此問題:

@page "/"
@using Microsoft.AspNetCore.Components.WebAssembly.Hosting
@inject IServiceProvider Services

<PageTitle>Home</PageTitle>

<h1>Home</h1>

<p>
    <b>Environment:</b> @environmentName
</p>

@code {
    private string? environmentName;

    protected override void OnInitialized()
    {
        if (Services.GetService<IWebAssemblyHostEnvironment>() is { } env)
        {
            environmentName = env.Environment;
        }
    }
}

不過,如果您的邏輯在預先轉譯期間要求值,上述方法就不實用。

如果您為元件停用預先轉譯,也可以避免此問題,但這是在許多情況下可能不符合您元件的規格時的一個極端方法。

有三個方法可供您用來解決此案例。 以下列出這些方法,從最建議到最不建議:

  • 建議用於共用架構服務:對於只未在主要專案中註冊伺服器端的共用架構服務,請在主要專案中註冊服務,以在預先轉譯期間提供這些服務。 如需此案例的範例,請參閱從 ASP.NET Core Blazor 應用程式呼叫 Web API 中的 HttpClient 服務指導。

  • 建議用於共用架構以外的服務:為伺服器上的服務建立自訂服務實作。 在 .Client 專案的互動式元件中正常使用服務。 如需此方法的示範,請參閱 ASP.NET Core Blazor 環境

  • 建立服務抽象概念,並在 .Client 和伺服器專案中建立服務的實作。 在每個專案中註冊服務。 在元件中插入自訂服務。

  • 您可以在伺服器上預先轉譯時,將 .Client 專案套件參考新增至伺服器端套件,並回到使用伺服器端 API。

探索來自其他組件的元件

其他組件必須向 Blazor 架構揭露,才能探索參考專案中可路由的 Razor 元件。 如需詳細資訊,請參閱 ASP.NET Core Blazor 路由和瀏覽

沒有剩餘的互動式伺服器元件時關閉線路

互動式伺服器元件會使用與瀏覽器的即時連線來處理 Web UI 事件,稱為線路。 當轉譯根互動式伺服器元件時,會建立線路及其相關聯的狀態。 當頁面上沒有剩餘的互動式伺服器元件時,線路會關閉,進而釋放伺服器資源。

自訂速記轉譯模式

@rendermode 指示詞會採用單一參數,這是類型為 IComponentRenderMode 的靜態執行個體。 @rendermode 指示詞屬性可以採用任何轉譯模式執行個體,無論是否為靜態。 Blazor 架構提供 RenderMode 靜態類別,並提供一些預先定義的轉譯模式以便使用,但您可以自行建立。

一般而言,元件會使用下列 @rendermode 指示詞來停用預先轉譯

@rendermode @(new InteractiveServerRenderMode(prerender: false))

不過,請考量下列範例,其會建立簡短的互動式伺服器端轉譯模式,而未透過應用程式的 _Imports 檔案 (Components/_Imports.razor) 預先轉譯:

public static IComponentRenderMode InteractiveServerWithoutPrerendering { get; } = 
    new InteractiveServerRenderMode(prerender: false);

Components 資料夾的元件中使用簡短轉譯模式:

@rendermode InteractiveServerWithoutPrerendering

或者,單一元件執行個體可以透過私人欄位定義自訂轉譯模式:

@rendermode interactiveServerWithoutPrerendering

...

@code {
    private static IComponentRenderMode interactiveServerWithoutPrerendering = 
        new InteractiveServerRenderMode(prerender: false);
}

目前,速記轉譯模式方法可能只適用於減少指定 prerender 旗標的詳細資訊。 如果其他旗標可供互動式轉譯使用,而且您想要使用不同旗標組合建立速記轉譯模式,則速記方法將來可能更有用。

透過最上層匯入檔案 (_Imports.razor) 的服務插入

本節僅適用 Blazor Web 應用程式。

Components 資料夾 (Components/_Imports.razor) 中的最上層匯入檔案會將其參考插入資料夾階層中的所有元件,其中包括 App 元件 (App.razor)。 App 元件一律會以靜態方式轉譯,即使停用頁面元件的預先轉譯也一樣。 因此,透過最上層匯入檔案插入服務會導致在頁面元件中解析服務的兩個執行個體

若要解決此案例,請將服務插入放在 Pages 資料夾 (Components/Pages/_Imports.razor) 的新匯入檔案中。 從該位置,服務只會在頁面元件中解析一次。

其他資源