備註
這不是本文的最新版本。 關於目前版本,請參閱 本文的 .NET 10 版本。
警告
此版本的 ASP.NET Core 已不再受支援。 如需詳細資訊,請參閱 .NET 和 .NET Core 支援政策。 如需目前的版本,請參閱 本文的 .NET 9 版本。
本文說明在伺服器端 Blazor 案例中維護用戶數據(狀態)的常見方法。
維護使用者狀態
伺服器端 Blazor 是具狀態的應用程式架構。 大部分時候,應用程式會維護與伺服器的連線。 使用者的狀態會保留在線路的伺服器記憶體中。
在線路中保留的使用者狀態範例包括:
- 元件執行個體的階層結構及其在已渲染的 UI 中最新的渲染輸出。
- 元件執行個體中的欄位和屬性值。
- 資料存放在相依性插入 (DI) 服務執行個體中,且範圍限定於線路。
您也可以透過 JavaScript Interop 呼叫,在瀏覽器記憶體集的 JavaScript 變數中找到使用者狀態。
如果使用者遇到暫時的網路連線遺失,Blazor 會嘗試以原始狀態將使用者重新連線到其原始線路。 不過,將使用者重新連線到其在伺服器記憶體中的原始線路並不一定可行:
- 伺服器無法永遠保留中斷連線的線路。 伺服器在逾時或伺服器承受記憶體不足的壓力時,必須釋放已斷開的連線。
- 在多伺服器、負載平衡的部署環境中,當不再需要處理整體要求量時,個別伺服器可能會失敗或自動移除。 當使用者嘗試重新連線時,使用者的原始伺服器處理要求可能會變成無法使用。
- 使用者可能會關閉並重新開啟其瀏覽器或重新載入頁面,這會移除瀏覽器記憶體中保留的任何狀態。 例如,透過 JavaScript Interop 呼叫設定的 JavaScript 變數值會遺失。
當用戶無法重新連線到其原始線路時,使用者會收到新初始化狀態的新線路。 這相當於關閉並重新開啟桌面應用程式。
保存用戶狀態的時機
狀態持續性並非自動。 開發應用程式以實作具狀態資料持續性時,您必須採取一些步驟。
一般而言,會在使用者積極創建資料的電路之間維護狀態,而不僅僅是讀取已經存在的資料。
通常只有使用者花費大量精力建立的高價值狀態才需要資料持續性。 儲存狀態可節省時間或協助商務工作:
- 多階段 Web 表單:如果使用者的狀態遺失,必須重新輸入已完成的數個階段的資料,對使用者而言相當耗時。 如果使用者離開表單並在稍後返回,則在此案例中就會失去狀態。
- 購物車:可以維護應用程式中任何具有商業重要性並能代表潛在營收的元件。 失去狀態的使用者,因此他們的購物車,可能會在稍後返回網站時購買較少的產品或服務。
應用程式只能保存應用程式狀態。 UI 無法被儲存,例如元件實例及其渲染樹。 元件和渲染樹通常無法序列化。 若要保存 UI 狀態 (例如樹狀檢視控制項的展開節點),應用程式必須使用自訂程式碼,將 UI 狀態的行為模型化為可序列化的應用程式狀態。
線路狀態持續性
在伺服器端轉譯期間, Blazor Web App只要未觸發完整頁面重新整理,就可以在長時間或主動暫停伺服器連線時,保存使用者的會話(線路)狀態。 這可讓使用者在下列案例中繼續其會話,而不會遺失未儲存的工作:
- 瀏覽器索引標籤限制
- 行動裝置使用者切換應用程式
- 網路中斷
- 主動式資源管理(暫停非作用中的線路)
- 增強的導航
如果線路狀態可以保存,然後稍後繼續,則可以釋放伺服器資源:
- 即使中斷連線,線路仍可能會繼續執行工作,並取用CPU、記憶體和其他資源。 保存狀態只會耗用開發人員所控制的固定記憶體數量。
- 保存狀態代表應用程式所耗用的記憶體子集,因此伺服器不需要追蹤應用程式的元件和其他伺服器端物件。
狀態會針對兩個情境儲存:
- 元件狀態:元件用於互動式伺服器轉譯的狀態,例如,從資料庫擷取的項目清單,或使用者正在填寫的表單。
- 作用域服務:在伺服器端服務中保存的狀態數據,例如,當前使用者。
條件:
- 此功能僅適用於互動式伺服器轉譯。
- 如果使用者重新整理頁面(應用程式),保存狀態會遺失。
- 狀態必須是 JSON 可串行化。 循環參考或 ORM 實體可能無法正確序列化。
- 在迴圈轉譯元件時,使用
@key來確保唯一性,避免索引鍵衝突。 - 只保存必要的狀態。 儲存過多的數據可能會影響效能。
- 沒有自動休眠。 您必須選擇加入並明確設定狀態保持。
- 不保證復原。 如果狀態的持久性失敗,應用程式會回退到離線的預設體驗。
當在AddInteractiveServerComponents檔案中呼叫AddRazorComponentsProgram時,狀態持續性會被預設啟用。
MemoryCache 是單一應用程式實例的預設記憶體實作,並儲存最多1,000個保存的線路兩個小時,這是可設定的。
使用下列選項來變更記憶體內部提供者的預設值:
-
PersistedCircuitInMemoryMaxRetained (
{CIRCUIT COUNT}佔位元):要保有的線路數目上限。 默認值為 1,000 個線路。 例如,使用2000來保留最多 2,000 個線路的狀態。 -
PersistedCircuitInMemoryRetentionPeriod (
{RETENTION PERIOD}佔位元):保留期間上限為 TimeSpan。 預設為 2 小時。 例如,使用TimeSpan.FromHours(3)作為 3 小時的保留期間。
services.Configure<CircuitOptions>(options =>
{
options.PersistedCircuitInMemoryMaxRetained = {CIRCUIT COUNT};
options.PersistedCircuitInMemoryRetentionPeriod = {RETENTION PERIOD};
});
跨線路保存元件狀態建置在現有的 PersistentComponentState API 之上,這會繼續保存採用互動式轉譯模式之預先呈現元件的狀態。 如需詳細資訊,請參閱 ASP.NET Core Blazor 預先呈現的狀態持續性。
[注意]保留預先呈現的元件狀態適用於任何互動式轉譯模式,但線路狀態持續性僅適用於 互動式伺服器 轉譯模式。
使用[PersistentState]屬性註記元件屬性,以啟用電路狀態保存。 下列範例也會使用指令屬性將項目@key鍵入,以提供每個元件實例的唯一識別碼:
@foreach (var item in Items)
{
<ItemDisplay @key="@($"unique-prefix-{item.Id}")" Item="item" />
}
@code {
[PersistentState]
public List<Item> Items { get; set; }
protected override async Task OnInitializedAsync()
{
Items ??= await LoadItemsAsync();
}
}
若要保存範圍服務的狀態,請使用[PersistentState]屬性標註服務屬性,將服務新增至服務集合,然後使用該服務呼叫RegisterPersistentService擴充方法:
public class CustomUserService
{
[PersistentState]
public string UserData { get; set; }
}
services.AddScoped<CustomUserService>();
services.AddRazorComponents()
.AddInteractiveServerComponents()
.RegisterPersistentService<CustomUserService>(RenderMode.InteractiveAuto);
[注意] 上述範例會在服務用於互動式伺服器和互動式 WebAssembly 的元件預先呈現時,保存
UserData狀態,因為RenderMode.InteractiveAuto已指定為 RegisterPersistentService。 不過,線路狀態持續性僅適用於 互動式伺服器 轉譯模式。
若要處理分散式狀態持續性(並在設定時作為默認狀態持續性機制),請將 (API:) HybridCache指派HybridCache給應用程式,以設定自己的持續性期間 (PersistedCircuitDistributedRetentionPeriod預設為 8 小時)。
HybridCache 被使用是因為它提供了一種不需要為每個儲存提供者使用個別套件的分散式儲存統一方法。
在下列範例中,將使用 HybridCache 儲存提供者來實作 。
services.AddHybridCache()
.AddRedis("{CONNECTION STRING}");
services.AddRazorComponents()
.AddInteractiveServerComponents();
在前面的範例中,{CONNECTION STRING} 佔位符代表 Redis 快取連接字串,應該使用安全的方法提供,例如在開發環境中使用 Secret Manager 工具,或在任何環境中 for Azure 部署的應用程式搭配 Azure 受管身份 使用 Azure Key Vault。
暫停和繼續線路
暫停和繼續線路,以實作可改善應用程式延展性的自定義原則。
暫停線路會將線路的詳細數據儲存在用戶端瀏覽器記憶體中,並收回線路,以釋放伺服器資源。 繼續線路會建立新的線路,並使用持續性狀態將其初始化。
從 JavaScript 事件處理程式:
- 呼叫
Blazor.pause以暫停線路。 - 呼叫
Blazor.resume以繼續線路。
下列範例假設看不到的應用程式不需要線路:
window.addEventListener('visibilitychange', () => {
if (document.visibilityState === 'hidden') {
Blazor.pause();
} else if (document.visibilityState === 'visible') {
Blazor.resume();
}
});
保存跨線路狀態
一般而言,會在使用者積極創建資料的電路之間維護狀態,而不僅僅是讀取已經存在的資料。
若要跨線路保留狀態,應用程式必須將資料保存到伺服器記憶體以外的其他儲存位置。 狀態持續性並非自動。 開發應用程式以實作具狀態資料持續性時,您必須採取一些步驟。
通常只有使用者花費大量精力建立的高價值狀態才需要資料持續性。 在下列範例中,保存狀態可節省時間,或協助商務工作:
- 多階段 Web 表單:如果使用者的狀態遺失,必須重新輸入已完成的數個階段的資料,對使用者而言相當耗時。 如果使用者離開表單並在稍後返回,則在此案例中就會失去狀態。
- 購物車:可以維護應用程式中任何具有商業重要性並能代表潛在營收的元件。 失去狀態的使用者連同他們的購物車,在稍後返回網站時,可能會購買較少的產品或服務。
應用程式只能保存應用程式狀態。 UI 無法被儲存,例如元件實例及其渲染樹。 元件和渲染樹通常無法序列化。 若要保存 UI 狀態 (例如樹狀檢視控制項的展開節點),應用程式必須使用自訂程式碼,將 UI 狀態的行為模型化為可序列化的應用程式狀態。
伺服器端儲存體
針對跨越多個使用者和裝置的永久資料持續性,應用程式可以使用伺服器端儲存體。 這些選項包括:
- Blob 儲存服務
- 鍵值儲存
- 關聯式資料庫
- 資料表存儲
儲存資料之後,會保留使用者的狀態,並可在任何新的線路中使用。
如需 Azure 資料儲存體選項的詳細資訊,請參閱下列各項:
瀏覽器儲存體
如需詳細資訊,請參閱 使用受保護的瀏覽器記憶體 ASP.NET 核心 Blazor 狀態管理。