預先轉譯 ASP.NET Core Razor 元件
本文說明 Blazor Web App中伺服器轉譯元件的 Razor 元件預先轉譯案例。
預先轉譯是伺服器上初始轉譯頁面內容,而不需要為轉譯的控制項啟用事件處理常式的程序。 伺服器會盡快輸出頁面的 HTML UI,以回應初始要求,如此可改善應用程式對使用者的回應速度。 預先轉譯也可改善搜尋引擎最佳化 (SEO),方法是轉譯搜尋引擎用來計算頁面排名的初始 HTTP 回應的內容。
保存預先轉譯的狀態
若未保存預先轉譯的狀態,在預先轉譯期間所使用的狀態會遺失,而且必須在應用程式完全載入時重建。 如果以非同步方式建立任何狀態,UI 可能會閃爍,因為在元件重新轉譯時會取代預先轉譯的 UI。
請考慮下列 PrerenderedCounter1
計數器元件。 元件在 OnInitialized
生命週期方法中預先轉譯期間設定初始隨機計數器值。 建立與用戶端的 SignalR 連線之後,元件會重新轉譯,並在第二次執行 OnInitialized
時取代初始計數值。
PrerenderedCounter1.razor
:
@page "/prerendered-counter-1"
@rendermode @(new InteractiveServerRenderMode(prerender: true))
@inject ILogger<PrerenderedCounter1> Logger
<PageTitle>Prerendered Counter 1</PageTitle>
<h1>Prerendered Counter 1</h1>
<p role="status">Current count: @currentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@code {
private int currentCount;
protected override void OnInitialized()
{
currentCount = Random.Shared.Next(100);
Logger.LogInformation("currentCount set to {Count}", currentCount);
}
private void IncrementCount() => currentCount++;
}
執行應用程式並檢查來自元件的記錄: 以下是範例輸出。
注意
如果應用程式採用互動式 (增強式) 路由,且透過內部導覽到達頁面,則不會進行預先轉譯。 因此,您必須對 PrerenderedCounter1
元件執行完整頁面重新載入,才能看到下列輸出。
info: BlazorSample.Components.Pages.PrerenderedCounter1[0]
currentCount set to 41
info: BlazorSample.Components.Pages.PrerenderedCounter1[0]
currentCount set to 92
第一個記錄的計數會在預先轉譯期間發生。 重新轉譯元件後,會再次設定此計數。 當計數從 41 更新為 92 時,UI 中也會閃爍。
若要在預先轉譯期間保留計數器的初始值,Blazor 會使用 PersistentComponentState 服務支援在預先轉譯的頁面中保存狀態 (以及針對內嵌至 Razor Pages 或 MVC 應用程式的頁面或檢視中的元件,使用 保存元件狀態標記協助程式)。
若要保留預先轉譯的狀態,請決定要使用 PersistentComponentState 服務保存哪個狀態。 PersistentComponentState.RegisterOnPersisting 會註冊回呼,以在應用程式暫停前保存元件狀態。 應用程式繼續時會擷取此狀態。
下列範例示範一般模式:
{TYPE}
預留位置代表要保存的資料類型。{TOKEN}
預留位置是狀態識別碼字串。 請考慮使用nameof({VARIABLE})
,其中{VARIABLE}
預留位置是保存狀態的變數名稱。 針對狀態識別碼使用nameof()
可避免使用引號字串。
@implements IDisposable
@inject PersistentComponentState ApplicationState
...
@code {
private {TYPE} data;
private PersistingComponentStateSubscription persistingSubscription;
protected override async Task OnInitializedAsync()
{
persistingSubscription =
ApplicationState.RegisterOnPersisting(PersistData);
if (!ApplicationState.TryTakeFromJson<{TYPE}>(
"{TOKEN}", out var restored))
{
data = await ...;
}
else
{
data = restored!;
}
}
private Task PersistData()
{
ApplicationState.PersistAsJson("{TOKEN}", data);
return Task.CompletedTask;
}
void IDisposable.Dispose()
{
persistingSubscription.Dispose();
}
}
下列計數器元件範例會在預先轉譯期間保存計數器狀態,並擷取要初始化元件的狀態。
PrerenderedCounter2.razor
:
@page "/prerendered-counter-2"
@implements IDisposable
@inject ILogger<PrerenderedCounter2> Logger
@inject PersistentComponentState ApplicationState
<PageTitle>Prerendered Counter 2</PageTitle>
<h1>Prerendered Counter 2</h1>
<p role="status">Current count: @currentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@code {
private int currentCount;
private PersistingComponentStateSubscription persistingSubscription;
protected override void OnInitialized()
{
persistingSubscription =
ApplicationState.RegisterOnPersisting(PersistCount);
if (!ApplicationState.TryTakeFromJson<int>(
nameof(currentCount), out var restoredCount))
{
currentCount = Random.Shared.Next(100);
Logger.LogInformation("currentCount set to {Count}", currentCount);
}
else
{
currentCount = restoredCount!;
Logger.LogInformation("currentCount restored to {Count}", currentCount);
}
}
private Task PersistCount()
{
ApplicationState.PersistAsJson(nameof(currentCount), currentCount);
return Task.CompletedTask;
}
void IDisposable.Dispose() => persistingSubscription.Dispose();
private void IncrementCount() => currentCount++;
}
當元件執行時,currentCount
只會在預先轉譯期間設定一次。 重新轉譯元件時,會還原此值。 以下是範例輸出。
注意
如果應用程式採用互動式 (增強式) 路由,且透過內部導覽到達頁面,則不會進行預先轉譯。 因此,您必須對 PrerenderedCounter2
元件執行完整頁面重新載入,才能看到下列輸出。
info: BlazorSample.Components.Pages.PrerenderedCounter2[0]
currentCount set to 96
info: BlazorSample.Components.Pages.PrerenderedCounter2[0]
currentCount restored to 96
在預先轉譯期間使用相同的狀態初始化元件,任何昂貴的初始化步驟只會執行一次。 轉譯的 UI 也會符合預先轉譯的 UI,因此瀏覽器中不會發生閃爍。
保存的預先呈現狀態會傳送至用戶端,用來還原元件狀態。 在用戶端轉譯 (CSR, ) 期間, InteractiveWebAssembly
數據會公開給瀏覽器,且不得包含機密的私人資訊。 在互動式伺服器端轉譯期間(互動式 SSR, InteractiveServer
), ASP.NET Core Data Protection 可確保數據安全地傳輸。 轉 InteractiveAuto
譯模式結合了 WebAssembly 和伺服器互動功能,因此必須考慮數據暴露在瀏覽器上,如同 CSR 案例一樣。
嵌入至頁面和檢視的元件(Razor Pages/MVC)
對於內嵌至 Razor Pages 和 MVC 應用程式的頁面或檢視中的元件,您必須在應用程式版面配置的結尾 </body>
標記內新增具有 <persist-component-state />
HTML 標記的保存元件狀態標記協助程式。 只有 Razor Pages 和 MVC 應用程式才需要此協助程式。 如需詳細資訊,請參閱 ASP.NET Core 中的保存元件狀態標記協助程式。
Pages/Shared/_Layout.cshtml
:
<body>
...
<persist-component-state />
</body>
互動式路由和預先轉譯
互動式路由 的內部瀏覽並不涉及向伺服器要求新的頁面內容。 因此,內部頁面要求不會發生預先轉譯。
此 PersistentComponentState 服務只能在初始頁面載入運作,而不會在 增強的頁面瀏覽事件之間運作。 如果應用程式執行完整(非增強的)瀏覽至使用永續性元件狀態的頁面,則當應用程式變成互動式時,會提供持續性狀態。 但是,如果已建立互動式線路,且對轉譯持續性元件狀態的頁面執行增強式瀏覽,則該狀態在現有的線路中不可使用。 PersistentComponentState 服務不知道增強的瀏覽,並且沒有機制可傳遞狀態更新至已執行的元件。
預先轉譯指引
預先轉譯指引會依主題在 Blazor 文件中組織。 下列連結涵蓋依主題設定的文件內的所有預先轉譯指引:
基礎
元件
- 在預先轉譯期間控制
<head>
內容 - 與預先轉譯相關的 Razor 元件生命週期主題
- 元件初始化 (
OnInitialized{Async}
) - 元件轉譯之後 (
OnAfterRender{Async}
) - 預先轉譯之後的具狀態重新連線
- 使用 JavaScript Interop 預先轉譯:這一節也會出現在兩篇 JS Interop 文章中,這兩篇文章有關從 .NET 呼叫 JavaScript 及從 JavaScript 呼叫 .NET。
- 元件初始化 (
- QuickGrid 元件範例應用程式:Blazor 範例應用程式的 QuickGrid 裝載於 GitHub Pages 上。 多虧使用社群維護的
BlazorWasmPrerendering.Build
GitHub 專案進行靜態預先轉譯,網站才能快速載入。 - 將元件整合到 Razor Pages 和 MVC 應用程式時預先轉譯
- 在預先轉譯期間控制
驗證與授權
狀態管理:控制代碼預先轉譯:除了控制代碼預先轉譯一節以外,文章的其他幾節還包含預先轉譯的備註。