共用方式為


預呈現 ASP.NET Core Razor 元件

註釋 / 注意

這不是本文的最新版本。 關於目前版本,請參閱 本文的 .NET 10 版本

本文說明 Razor 和 Blazor Web App 應用程式中伺服器轉譯元件的元件Blazor Server預先呈現案例。

預先呈現 是從伺服器靜態轉譯頁面內容,以儘快將 HTML 傳遞至瀏覽器的程式。 在預先呈現的內容快速向使用者顯示之後,會轉譯具有作用中事件處理程式的互動式內容,並取代先前轉譯的任何內容。 預渲染還可以通過渲染搜索引擎用於計算頁面級別的初始 HTTP 響應內容來改善搜尋引擎最佳化(SEO)。

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

具有互動式路由的內部導覽不會使用預先轉譯,因為頁面已經是互動式的。 如需詳細資訊,請參閱 靜態與互動式路由互動式路由和預先轉譯

只有在元件以互動方式呈現之後,才會在預先呈現時呼叫元件生命週期事件。OnAfterRender{Async}

停用預先呈現

預先呈現可能會使應用程式複雜化,因為應用程式的 Razor 元件必須轉譯兩次:一次用於預先呈現,一次用於設定互動。 如果元件設定為在 WebAssembly 上執行,您也必須設計元件,以便從伺服器和客戶端執行這些元件。

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

  • <... @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 專案範本為基礎的應用程式,指派至整個應用程式的轉譯模式會在 Routes 元件 (App) 中使用 Components/App.razor 元件所在的位置指定。 下列範例會將應用程式的渲染模式設定為互動式伺服器,同時停用預先渲染功能:

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

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

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

不支援將根元件(例如 App 元件)透過根元件定義檔(@rendermode)頂端的 .razor 指示詞設為互動。 因此,App 元件無法直接停用預先轉譯。

使用上述技術停用預先呈現只會對最上層轉譯模式生效。 如果父元件指定轉譯模式,則會忽略其子系的預先轉譯設定。

保存預先轉譯的狀態

如果不保留預渲染的狀態,則預渲染過程中使用的狀態將丟失,並且在應用程序完全加載時必須重新創建。 如果任何狀態是非同步建立的,當元件重新渲染時,UI 可能會閃爍,因為預渲染的 UI 被取代。 如需如何在預先呈現期間保存狀態的指引,請參閱 ASP.NET Core Blazor 預先呈現的狀態持續性

用戶端服務在預先轉譯期間無法解決問題

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

例如,請考量在具有全球互動式 WebAssembly 或互動式自動呈現的 Home 專案中,.Client 中的以下 Blazor Web App 元件。 元件會嘗試插入 IWebAssemblyHostEnvironment 以取得環境的名稱。

@page "/"
@inject IWebAssemblyHostEnvironment Environment

<PageTitle>Home</PageTitle>

<h1>Home</h1>

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

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

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

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

請考慮下列任一方法來解決此案例:

除了在用戶端上,還要在伺服器上註冊該服務。

如果服務支援伺服器執行,除了用戶端之外,還要在伺服器上註冊服務,以便在預先轉譯期間可用。 如需此案例的範例,請參閱HttpClient文章的外部 Blazor Web App Web API一節中的服務指引

將應用程式可以在預渲染期間使用的服務注入

在某些情況下,應用程式可以在預先轉譯期間使用伺服器上的服務,並在用戶端上使用不同的服務。

例如,下列程式碼會藉由從 IHostEnvironment,取得Microsoft.Extensions.Hosting.Abstractions應用程式的環境,無論程式碼是在伺服器上還是在用戶端上執行:

private string? environmentName;

public Home(IHostEnvironment? serverEnvironment = null, 
    IWebAssemblyHostEnvironment? wasmEnvironment = null)
{
    environmentName = serverEnvironment?.EnvironmentName;
    environmentName ??= wasmEnvironment?.Environment;
}

不過,此方法會為用戶端專案新增不需要的額外相依性。

將服務設為選擇性

如果在使用下列任一方法進行預先轉譯期間不需要服務,請將服務設為選擇性。

下列範例使用建構函式插入 IWebAssemblyHostEnvironment

private string? environmentName;

public Home(IWebAssemblyHostEnvironment? env = null)
{
    environmentName = env?.Environment;
}

或者,如果服務可用,則可注入 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;
        }
    }
}

建立服務抽象概念

如果伺服器上需要不同的服務實作,請建立服務抽象概念,並在伺服器和用戶端專案中建立服務的實作。 在每個專案中註冊服務。 在需要時將自訂服務抽象插入元件中。 然後,元件完全依賴於自訂服務抽象。

在的情況下 IWebAssemblyHostEnvironment,我們可以重複使用現有的介面,而不是建立新的介面:

ServerHostEnvironment.cs

using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
using Microsoft.AspNetCore.Components;

public class ServerHostEnvironment(IWebHostEnvironment env, NavigationManager nav) : 
    IWebAssemblyHostEnvironment
{
    public string Environment => env.EnvironmentName;
    public string BaseAddress => nav.BaseUri;
}

在伺服器專案的 Program 檔案中,註冊服務:

builder.Services.TryAddScoped<IWebAssemblyHostEnvironment, ServerHostEnvironment>();

此時, IWebAssemblyHostEnvironment 服務可以 注入到交互式 WebAssembly 或 Auto 組件中,該組件也是從服務器預渲染的

停用元件的預先渲染

停用元件的預渲染功能或整個應用程式的預渲染。 如需詳細資訊,請參閱 停用預先轉譯 一節。