správa základního Blazor stavu ASP.NET
Poznámka:
Toto není nejnovější verze tohoto článku. Aktuální verzi najdete v tomto článku ve verzi .NET 9.
Upozorňující
Tato verze ASP.NET Core se už nepodporuje. Další informace najdete v zásadách podpory .NET a .NET Core. Aktuální verzi najdete v tomto článku ve verzi .NET 9.
Důležité
Tyto informace se týkají předběžného vydání produktu, který může být podstatně změněn před komerčním vydáním. Microsoft neposkytuje žádné záruky, výslovné ani předpokládané, týkající se zde uváděných informací.
Aktuální verzi najdete v tomto článku ve verzi .NET 9.
Tento článek popisuje běžné přístupy k údržbě dat (stavu) uživatele při používání aplikace a napříč relacemi prohlížeče.
Poznámka:
Příklady kódu v tomto článku přijímají referenční typy s možnou hodnotou null (NRT) a statickou analýzu stavu null-stav kompilátoru .NET, které jsou podporovány v ASP.NET Core v .NET 6 nebo novější. Při cílení na ASP.NET Core 5.0 nebo starší odeberte označení typu null z?
typů v příkladech článku.
Udržovat stav uživatele
Na straně Blazor serveru je stavová aplikační architektura. Ve většině případů aplikace udržuje připojení k serveru. Stav uživatele se uchovává v paměti serveru v okruhu.
Mezi příklady stavu uživatele uchovávaného v okruhu patří:
- Hierarchie instancí komponent a jejich nejnovější výstup vykreslení v vykresleném uživatelském rozhraní.
- Hodnoty polí a vlastností v instancích komponent.
- Data uložená v instancích služby injektáže závislostí (DI), které jsou vymezeny na okruh.
Stav uživatele se také může nacházet v proměnných JavaScriptu v sadě paměti prohlížeče prostřednictvím volání zprostředkovatele komunikace JavaScriptu.
Pokud uživatel dojde k dočasné ztrátě síťového připojení, Blazor pokusí se uživatele znovu připojit k původnímu okruhu s původním stavem. Opětovné připojení uživatele k původnímu okruhu v paměti serveru ale není vždy možné:
- Server nemůže trvale zachovat odpojený okruh. Server musí po vypršení časového limitu uvolnit odpojený okruh nebo když je server pod tlakem paměti.
- V prostředích nasazení s více servery s vyrovnáváním zatížení může dojít k selhání jednotlivých serverů nebo k jejich automatickému odebrání, pokud už není potřeba zpracovat celkový objem požadavků. Původní požadavky na zpracování serveru pro uživatele můžou být nedostupné, když se uživatel pokusí znovu připojit.
- Uživatel může zavřít a znovu otevřít prohlížeč nebo znovu načíst stránku, která odebere jakýkoli stav uložený v paměti prohlížeče. Například hodnoty proměnných Jazyka JavaScript nastavené prostřednictvím volání zprostředkovatele komunikace JavaScriptu se ztratí.
Když se uživatel nemůže znovu připojit k původnímu okruhu, uživatel obdrží nový okruh s prázdným stavem. To odpovídá zavření a opětovnému otevření desktopové aplikace.
Zachování stavu napříč okruhy
Obecně platí, že zachovejte stav napříč okruhy, ve kterých uživatelé aktivně vytvářejí data, a ne jednoduše čtou data, která už existují.
Aby se zachoval stav napříč okruhy, musí aplikace uchovávat data do jiného umístění úložiště, než je paměť serveru. Trvalost stavu není automatická. Při vývoji aplikace musíte provést kroky pro implementaci stavové trvalosti dat.
Trvalost dat se obvykle vyžaduje jenom pro vysoce hodnotný stav, kdy uživatelé vynaložili úsilí na vytvoření. V následujících příkladech zachování stavu šetří čas nebo pomůcky v komerčních aktivitách:
- Vícekrokové webové formuláře: Je časově náročné, aby uživatel znovu zadal data pro několik dokončených kroků webového formuláře s více kroky, pokud dojde ke ztrátě jejich stavu. Uživatel v tomto scénáři ztratí stav, pokud přejde mimo formulář a vrátí se později.
- Nákupní košíky: Všechny komerčně důležité součásti aplikace, které představují potenciální výnosy, je možné zachovat. Uživatel, který ztratí svůj stav, a tedy nákupní košík, může při pozdějším návratu na web zakoupit méně produktů nebo služeb.
Aplikace může zachovat pouze stav aplikace. UI nelze zachovat, například instance komponent a jejich vykreslovací stromy. Komponenty a vykreslovací stromy nejsou obecně serializovatelné. Pokud chcete zachovat stav uživatelského rozhraní, například rozbalené uzly ovládacího prvku stromového zobrazení, musí aplikace použít vlastní kód k modelování chování stavu uživatelského rozhraní jako serializovatelného stavu aplikace.
Kde zachovat stav
Pro zachování stavu existují běžná umístění:
Úložiště na straně serveru
Pro trvalost dat, která zahrnuje více uživatelů a zařízení, může aplikace používat úložiště na straně serveru. K dispozici jsou následující možnosti:
- Blob Storage
- Úložiště klíč-hodnota
- Relační databáze
- Table Storage
Po uložení dat se stav uživatele zachová a zpřístupní v jakémkoli novém okruhu.
Další informace o možnostech úložiště dat Azure najdete v následujících tématech:
Adresa URL
U přechodných dat představujících stav navigace modelujte data jako součást adresy URL. Mezi příklady modelu stavu uživatele v adrese URL patří:
- ID zobrazené entity.
- Číslo aktuální stránky v stránkované mřížce
Obsah adresního řádku prohlížeče se zachová:
- Pokud uživatel stránku znovu načte ručně.
- Pokud se webový server stane nedostupným a uživatel je nucen znovu načíst stránku, aby se mohl připojit k jinému serveru.
Informace o definování vzorů adres URL pomocí @page
direktivy najdete v tématu ASP.NET Blazor Základní směrování a navigace.
Úložiště prohlížeče
U přechodných dat, která uživatel aktivně vytváří, je běžně používané umístění úložiště umístěním prohlížeče localStorage
a sessionStorage
kolekcí:
-
localStorage
je vymezena na instanci prohlížeče. Pokud uživatel stránku znovu načte nebo ji zavře a znovu otevře prohlížeč, stav se zachová. Pokud uživatel otevře více karet prohlížeče, stav se na kartách sdílí. Data se uchovávají ažlocalStorage
do explicitního vymazání. DatalocalStorage
pro dokument načtený v relaci "privátního procházení" nebo "anonymní" se vymažou, když se zavře poslední soukromá karta. -
sessionStorage
je vymezený na kartu prohlížeče. Pokud uživatel kartu znovu načte, stav se zachová. Pokud uživatel kartu nebo prohlížeč zavře, stav se ztratí. Pokud uživatel otevře více karet prohlížeče, každá karta má svou vlastní nezávislou verzi dat.
Obecně platí, sessionStorage
že je bezpečnější používat.
sessionStorage
zabraňuje riziku, že uživatel otevře více karet a narazí na následující:
- Chyby ve stavové úložišti na kartách
- Matoucí chování při přepsání stavu jiných karet tabulátoru
localStorage
je lepší volbou, pokud aplikace musí zachovat stav při zavření a opětovném otevření prohlížeče.
Upozornění pro použití úložiště prohlížeče:
- Podobně jako použití databáze na straně serveru jsou načítání a ukládání dat asynchronní.
- Požadovaná stránka v prohlížeči neexistuje během předrenderingu, takže během předkreslování není místní úložiště dostupné.
- Úložiště několika kilobajtů dat je vhodné zachovat pro aplikace na straně Blazor serveru. Kromě několika kilobajtů je potřeba zvážit dopad na výkon, protože se data načítají a ukládají v síti.
- Uživatelé můžou data zobrazit nebo zfalšovat. ASP.NET Základní ochrana dat může riziko zmírnit. Například ASP.NET Core Protected Browser Storage používá ASP.NET Základní ochrana dat.
Balíčky NuGet třetích stran poskytují rozhraní API pro práci s localStorage
a sessionStorage
. Je vhodné zvážit výběr balíčku, který transparentně používá ASP.NET Core Data Protection. Ochrana dat šifruje uložená data a snižuje potenciální riziko manipulace s uloženými daty. Pokud jsou serializovaná data JSON uložená ve formátu prostého textu, můžou uživatelé zobrazit data pomocí vývojářských nástrojů prohlížeče a také upravit uložená data. Zabezpečení triviálních dat není problém. Například čtení nebo úprava uložené barvy prvku uživatelského rozhraní není významným bezpečnostním rizikem pro uživatele nebo organizaci. Vyhněte se tomu, aby uživatelé mohli kontrolovat nebo manipulovat s citlivými daty.
úložiště chráněného prohlížečem ASP.NET Core
ASP.NET Core Protected Browser Storage využívá ASP.NET základní ochranu dat pro localStorage
a sessionStorage
.
Poznámka:
Chráněné úložiště prohlížeče spoléhá na ASP.NET Core Data Protection a podporuje se jenom pro aplikace na straně Blazor serveru.
Upozorňující
Microsoft.AspNetCore.ProtectedBrowserStorage
je nepodporovaný experimentální balíček, který není určený pro produkční použití.
Balíček je k dispozici pouze pro použití v aplikacích ASP.NET Core 3.1.
Konfigurace
Přidejte odkaz na balíček .
Microsoft.AspNetCore.ProtectedBrowserStorage
Poznámka:
Pokyny k přidávání balíčků do aplikací .NET najdete v článcích v části Instalace a správa balíčků na webu Pracovní postup používání balíčků (dokumentace k NuGetu). Ověřte správné verze balíčků na NuGet.org.
_Host.cshtml
Do souboru přidejte do koncové</body>
značky následující skript:<script src="_content/Microsoft.AspNetCore.ProtectedBrowserStorage/protectedBrowserStorage.js"></script>
Startup.ConfigureServices
VoláníAddProtectedBrowserStorage
pro přidánílocalStorage
asessionStorage
služby do kolekce služeb:services.AddProtectedBrowserStorage();
Ukládání a načítání dat v rámci komponenty
V jakékoli komponentě, která vyžaduje načítání nebo ukládání dat do úložiště prohlížeče, použijte direktivu @inject
k vložení instance některé z následujících:
ProtectedLocalStorage
ProtectedSessionStorage
Volba závisí na umístění úložiště prohlížeče, které chcete použít. V následujícím příkladu sessionStorage
se používá:
@using Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage
@inject ProtectedSessionStorage ProtectedSessionStore
@using Microsoft.AspNetCore.ProtectedBrowserStorage
@inject ProtectedSessionStorage ProtectedSessionStore
Direktivu @using
lze umístit do souboru aplikace _Imports.razor
namísto komponenty.
_Imports.razor
Použití souboru zpřístupňuje obor názvů větším segmentům aplikace nebo celé aplikace.
Pokud chcete zachovat currentCount
hodnotu v Counter
komponentě aplikace naBlazorzákladě šablony projektu, upravte metodu IncrementCount
tak, aby používalaProtectedSessionStore.SetAsync
:
private async Task IncrementCount()
{
currentCount++;
await ProtectedSessionStore.SetAsync("count", currentCount);
}
Ve větších, realističtějších aplikacích je úložiště jednotlivých polí nepravděpodobné. Aplikace budou pravděpodobně ukládat celé objekty modelu, které obsahují složitý stav.
ProtectedSessionStore
automaticky serializuje a deserializuje data JSON pro ukládání složitých stavových objektů.
V předchozím příkladu currentCount
kódu se data ukládají jako sessionStorage['count']
v prohlížeči uživatele. Data nejsou uložená ve formátu prostého textu, ale jsou chráněná pomocí ASP.NET Core Data Protection. Zašifrovaná data je možné zkontrolovat, pokud sessionStorage['count']
jsou vyhodnocena v konzole pro vývojáře prohlížeče.
Chcete-li obnovit currentCount
data, pokud se uživatel později vrátí do Counter
komponenty, včetně toho, zda je uživatel v novém okruhu, použijte ProtectedSessionStore.GetAsync
:
protected override async Task OnInitializedAsync()
{
var result = await ProtectedSessionStore.GetAsync<int>("count");
currentCount = result.Success ? result.Value : 0;
}
protected override async Task OnInitializedAsync()
{
currentCount = await ProtectedSessionStore.GetAsync<int>("count");
}
Pokud parametry komponenty zahrnují stav navigace, zavolejte ProtectedSessionStore.GetAsync
a přiřaďte výsledeknull
,OnParametersSetAsync nikoli OnInitializedAsync.
OnInitializedAsync je volána pouze jednou při první vytvoření instance komponenty.
OnInitializedAsync není znovu volána později, pokud uživatel přejde na jinou adresu URL a zůstane na stejné stránce. Další informace najdete v tématu Životní cyklus komponent ASP.NET Core Razor.
Upozorňující
Příklady v této části fungují jenom v případě, že server nemá povolené předběžné nastavení. Při povoleném předběžném generování se vygeneruje chyba s vysvětlením, že volání interop JavaScriptu nelze vydat, protože komponenta je předem vygenerována.
Buď zakažte předrendering, nebo přidejte další kód pro práci s předrenderingem. Další informace o psaní kódu, který funguje s předrenderingem, najdete v části Popisovač předrenderingu .
Zpracování stavu načítání
Vzhledem k tomu, že k úložišti prohlížeče se přistupuje asynchronně přes síťové připojení, je vždy čas před načtením dat a dostupným pro komponentu. Nejlepších výsledků dosáhnete tak, že během načítání vykreslíte zprávu místo zobrazení prázdných nebo výchozích dat.
Jedním z přístupů je sledovat, jestli jsou null
data , což znamená, že se data stále načítají. Ve výchozí Counter
komponentě se počet nachází v objektu int
.
int
private int? currentCount;
Místo nepodmíněného zobrazení počtu a Increment
tlačítka zobrazte tyto prvky pouze v případě, že jsou data načtena kontrolou HasValue:
@if (currentCount.HasValue)
{
<p>Current count: <strong>@currentCount</strong></p>
<button @onclick="IncrementCount">Increment</button>
}
else
{
<p>Loading...</p>
}
Zpracování předrenderingu
Během předkreslování:
- Interaktivní připojení k prohlížeči uživatele neexistuje.
- Prohlížeč zatím nemá stránku, ve které může spustit javascriptový kód.
localStorage
nebo sessionStorage
nejsou během předkreslování k dispozici. Pokud se komponenta pokusí pracovat s úložištěm, vygeneruje se chyba s vysvětlením, že volání interop JavaScriptu nelze vydat, protože komponenta je předem vygenerována.
Jedním ze způsobů, jak tuto chybu vyřešit, je zakázat předrendering. To je obvykle nejlepší volbou, pokud aplikace využívá velké využití úložiště založeného na prohlížeči. Předrenderování zvyšuje složitost a nemá pro aplikaci výhodu, protože aplikace nemůže předem vyřídit žádný užitečný obsah, dokud localStorage
nebude dostupný nebo sessionStorage
nebude k dispozici.
Chcete-li zakázat předběžné vykreslování, označte režim vykreslování s parametrem prerender
nastaveným na false
komponentu nejvyšší úrovně v hierarchii komponent aplikace, která není kořenovou komponentou.
Poznámka:
Interaktivní vytvoření kořenové komponenty, například App
komponenty, není podporováno. Proto není možné předřazování přímo zakázat komponentou App
.
U aplikací založených na Blazor Web App šabloně projektu je prerendering obvykle zakázán, pokud se komponenta Routes
používá v App
dané komponentě (Components/App.razor
):
<Routes @rendermode="new InteractiveServerRenderMode(prerender: false)" />
Zakažte také předběžné předkreslování pro komponentu HeadOutlet
:
<HeadOutlet @rendermode="new InteractiveServerRenderMode(prerender: false)" />
Chcete-li zakázat předkreslování, otevřete _Host.cshtml
soubor a změňte render-mode
atribut pomocné rutiny značky komponenty na Server:
<component type="typeof(App)" render-mode="Server" />
Pokud je předřažení zakázané, je předkreslování <head>
obsahu zakázané.
Předkreslování může být užitečné pro jiné stránky, které nepoužívají localStorage
nebo sessionStorage
. Pokud chcete zachovat předrendering, odložte operaci načítání, dokud nebude prohlížeč připojený k okruhu. Následuje příklad pro uložení hodnoty čítače:
@using Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage
@inject ProtectedLocalStorage ProtectedLocalStore
@if (isConnected)
{
<p>Current count: <strong>@currentCount</strong></p>
<button @onclick="IncrementCount">Increment</button>
}
else
{
<p>Loading...</p>
}
@code {
private int currentCount;
private bool isConnected;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
isConnected = true;
await LoadStateAsync();
StateHasChanged();
}
}
private async Task LoadStateAsync()
{
var result = await ProtectedLocalStore.GetAsync<int>("count");
currentCount = result.Success ? result.Value : 0;
}
private async Task IncrementCount()
{
currentCount++;
await ProtectedLocalStore.SetAsync("count", currentCount);
}
}
@using Microsoft.AspNetCore.ProtectedBrowserStorage
@inject ProtectedLocalStorage ProtectedLocalStore
@if (isConnected)
{
<p>Current count: <strong>@currentCount</strong></p>
<button @onclick="IncrementCount">Increment</button>
}
else
{
<p>Loading...</p>
}
@code {
private int currentCount = 0;
private bool isConnected = false;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
isConnected = true;
await LoadStateAsync();
StateHasChanged();
}
}
private async Task LoadStateAsync()
{
currentCount = await ProtectedLocalStore.GetAsync<int>("count");
}
private async Task IncrementCount()
{
currentCount++;
await ProtectedLocalStore.SetAsync("count", currentCount);
}
}
Oddělte zachování stavu do společného poskytovatele
Pokud mnoho komponent spoléhá na úložiště založené na prohlížeči, implementace kódu zprostředkovatele stavu mnohokrát vytvoří duplikaci kódu. Jednou z možností, jak se vyhnout duplikaci kódu, je vytvořit nadřazenou komponentu zprostředkovatele stavu, která zapouzdřuje logiku zprostředkovatele stavu. Podřízené komponenty mohou pracovat s trvalými daty bez ohledu na mechanismus trvalosti stavu.
V následujícím příkladu komponenty CounterStateProvider
se data čítače uchovávají v sessionStorage
a zpracovává fázi načítání tím, že nevykresluje podřízený obsah, dokud není načítání stavu dokončeno.
Komponenta CounterStateProvider
se zabývá předrenderováním tím, že nenačítá stav, dokud není komponenta vykreslena v rámci metody životního cyklu OnAfterRenderAsync
, která se během předrenderování nespustí.
Přístup v této části nemůže aktivovat opětovné spuštění více předplacených komponent na stejné stránce. Pokud jedna přihlášená komponenta změní stav, znovu se vykreslí a může zobrazit aktualizovaný stav, ale jiná komponenta na stejné stránce, která zobrazuje tento stav, zobrazuje zastaralá data, dokud se znovu nevykreslí. Proto je přístup popsaný v této části nejvhodnější pro použití stavu v jedné komponentě na stránce.
CounterStateProvider.razor
:
@using Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage
@inject ProtectedSessionStorage ProtectedSessionStore
@if (isLoaded)
{
<CascadingValue Value="this">
@ChildContent
</CascadingValue>
}
else
{
<p>Loading...</p>
}
@code {
private bool isLoaded;
[Parameter]
public RenderFragment? ChildContent { get; set; }
public int CurrentCount { get; set; }
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
isLoaded = true;
await LoadStateAsync();
StateHasChanged();
}
}
private async Task LoadStateAsync()
{
var result = await ProtectedSessionStore.GetAsync<int>("count");
CurrentCount = result.Success ? result.Value : 0;
isLoaded = true;
}
public async Task IncrementCount()
{
CurrentCount++;
await ProtectedSessionStore.SetAsync("count", CurrentCount);
}
}
@using Microsoft.AspNetCore.ProtectedBrowserStorage
@inject ProtectedSessionStorage ProtectedSessionStore
@if (isLoaded)
{
<CascadingValue Value="this">
@ChildContent
</CascadingValue>
}
else
{
<p>Loading...</p>
}
@code {
private bool isLoaded;
[Parameter]
public RenderFragment ChildContent { get; set; }
public int CurrentCount { get; set; }
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
isLoaded = true;
await LoadStateAsync();
StateHasChanged();
}
}
private async Task LoadStateAsync()
{
CurrentCount = await ProtectedSessionStore.GetAsync<int>("count");
isLoaded = true;
}
public async Task IncrementCount()
{
CurrentCount++;
await ProtectedSessionStore.SetAsync("count", CurrentCount);
}
}
Poznámka:
Další informace o RenderFragmentkomponentách RazorASP.NET Core.
Pokud chcete, aby byl stav přístupný pro všechny komponenty v aplikaci, zabalte CounterStateProvider
komponentu kolem Router komponenty (<Router>...</Router>
) pomocí Routes
globálního interaktivního vykreslování na straně serveru (interaktivní SSR).
V komponentě App
(Components/App.razor
):
<Routes @rendermode="InteractiveServer" />
V komponentě Routes
(Components/Routes.razor
):
Pokud chcete komponentu CounterStateProvider
použít, zabalte instanci komponenty kolem jakékoli jiné komponenty, která vyžaduje přístup ke stavu čítače. Pokud chcete, aby byl stav přístupný pro všechny komponenty v aplikaci, zabalte CounterStateProvider
komponentu RouterApp
kolem komponenty (App.razor
):
<CounterStateProvider>
<Router ...>
...
</Router>
</CounterStateProvider>
Poznámka:
S vydáním ASP.NET Core 5.0.1 a pro všechny další verze 5.x komponenta Router
zahrnuje parametr PreferExactMatches
nastavený na @true
. Další informace najdete v tématu Migrace z ASP.NET Core 3.1 na verzi 5.0.
Zabalené komponenty přijímají a mohou upravit trvalý stav čítače.
Counter
Následující komponenta implementuje vzor:
@page "/counter"
<p>Current count: <strong>@CounterStateProvider?.CurrentCount</strong></p>
<button @onclick="IncrementCount">Increment</button>
@code {
[CascadingParameter]
private CounterStateProvider? CounterStateProvider { get; set; }
private async Task IncrementCount()
{
if (CounterStateProvider is not null)
{
await CounterStateProvider.IncrementCount();
}
}
}
Předchozí komponenta není nutná k interakci ProtectedBrowserStorage
ani s fází načítání.
Obecně se doporučuje vzor nadřazené komponenty zprostředkovatele stavu:
- Pokud chcete využívat stav napříč mnoha komponentami.
- Pokud existuje jen jeden objekt stavu nejvyšší úrovně, který se má zachovat.
Pokud chcete zachovat mnoho různých stavových objektů a využívat různé podmnožina objektů na různých místech, je lepší se vyhnout globálnímu zachování stavu.
Stav uživatele vytvořený v Blazor WebAssembly aplikaci se uchovává v paměti prohlížeče.
Mezi příklady stavu uživatele uchovávaného v paměti prohlížeče patří:
- Hierarchie instancí komponent a jejich nejnovější výstup vykreslení v vykresleném uživatelském rozhraní.
- Hodnoty polí a vlastností v instancích komponent.
- Data uložená v instancích služby injektáže závislostí (DI).
- Hodnoty nastavené prostřednictvím volání zprostředkovatele komunikace JavaScriptu
Když uživatel zavře a znovu otevře prohlížeč nebo stránku znovu načte, ztratí se stav uživatele uložený v paměti prohlížeče.
Poznámka:
Protected Browser Storage (Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage obor názvů) spoléhá na ASP.NET Core Data Protection a podporuje se jenom pro aplikace na straně Blazor serveru.
Zachování stavu napříč relacemi prohlížeče
Obecně platí, že udržujte stav napříč relacemi prohlížeče, ve kterých uživatelé aktivně vytvářejí data, a ne jednoduše čtou data, která už existují.
Aby se zachoval stav napříč relacemi prohlížeče, musí aplikace uchovávat data v jiném umístění úložiště než v paměti prohlížeče. Trvalost stavu není automatická. Při vývoji aplikace musíte provést kroky pro implementaci stavové trvalosti dat.
Trvalost dat se obvykle vyžaduje jenom pro vysoce hodnotný stav, kdy uživatelé vynaložili úsilí na vytvoření. V následujících příkladech zachování stavu šetří čas nebo pomůcky v komerčních aktivitách:
- Vícekrokové webové formuláře: Je časově náročné, aby uživatel znovu zadal data pro několik dokončených kroků webového formuláře s více kroky, pokud dojde ke ztrátě jejich stavu. Uživatel v tomto scénáři ztratí stav, pokud přejde mimo formulář a vrátí se později.
- Nákupní košíky: Všechny komerčně důležité součásti aplikace, které představují potenciální výnosy, je možné zachovat. Uživatel, který ztratí svůj stav, a tedy nákupní košík, může při pozdějším návratu na web zakoupit méně produktů nebo služeb.
Aplikace může zachovat pouze stav aplikace. UI nelze zachovat, například instance komponent a jejich vykreslovací stromy. Komponenty a vykreslovací stromy nejsou obecně serializovatelné. Pokud chcete zachovat stav uživatelského rozhraní, například rozbalené uzly ovládacího prvku stromového zobrazení, musí aplikace použít vlastní kód k modelování chování stavu uživatelského rozhraní jako serializovatelného stavu aplikace.
Kde zachovat stav
Pro zachování stavu existují běžná umístění:
Úložiště na straně serveru
Pro trvalost dat, která pokrývá více uživatelů a zařízení, může aplikace používat nezávislé úložiště na straně serveru, ke kterému přistupuje prostřednictvím webového rozhraní API. K dispozici jsou následující možnosti:
- Blob Storage
- Úložiště klíč-hodnota
- Relační databáze
- Table Storage
Po uložení dat se stav uživatele zachová a zpřístupní v jakékoli nové relaci prohlížeče.
Vzhledem k tomu, že Blazor WebAssembly aplikace běží zcela v prohlížeči uživatele, vyžadují další opatření pro přístup k zabezpečeným externím systémům, jako jsou služby úložiště a databáze. Aplikace Blazor WebAssembly jsou zabezpečené stejným způsobem jako jednostránkové aplikace (SPA). Aplikace obvykle ověřuje uživatele prostřednictvím OAuth/OpenID Connect (OIDC) a pak komunikuje se službami úložiště a databázemi prostřednictvím volání webového rozhraní API do aplikace na straně serveru. Aplikace na straně serveru zprostředkuje přenos dat mezi Blazor WebAssembly aplikací a službou úložiště nebo databází. Aplikace Blazor WebAssembly udržuje dočasné připojení k aplikaci na straně serveru, zatímco aplikace na straně serveru má trvalé připojení k úložišti.
Další informace naleznete v následujících zdrojích:
- Volání webového rozhraní API z aplikace ASP.NET Core Blazor
- Zabezpečení ASP.NET Core Blazor WebAssembly
- Blazor Zabezpečení a Identity články
Další informace o možnostech úložiště dat Azure najdete v následujících tématech:
Adresa URL
U přechodných dat představujících stav navigace modelujte data jako součást adresy URL. Mezi příklady modelu stavu uživatele v adrese URL patří:
- ID zobrazené entity.
- Číslo aktuální stránky v stránkované mřížce
Obsah adresního řádku prohlížeče se zachová, pokud uživatel stránku znovu načte ručně.
Informace o definování vzorů adres URL pomocí @page
direktivy najdete v tématu ASP.NET Blazor Základní směrování a navigace.
Úložiště prohlížeče
U přechodných dat, která uživatel aktivně vytváří, je běžně používané umístění úložiště umístěním prohlížeče localStorage
a sessionStorage
kolekcí:
-
localStorage
je omezena v rámci instance prohlížeče. Pokud uživatel stránku znovu načte nebo ji zavře a znovu otevře prohlížeč, stav se zachová. Pokud uživatel otevře více karet prohlížeče, stav se na kartách sdílí. Data se uchovávají ažlocalStorage
do explicitního vymazání. DatalocalStorage
pro dokument načtený v relaci "privátního procházení" nebo "anonymní" se vymažou, když se zavře poslední soukromá karta. -
sessionStorage
je vymezený na kartu prohlížeče. Pokud uživatel kartu znovu načte, stav se zachová. Pokud uživatel kartu nebo prohlížeč zavře, stav se ztratí. Pokud uživatel otevře více karet prohlížeče, každá karta má svou vlastní nezávislou verzi dat.
Poznámka:
localStorage
a sessionStorage
dají se používat v Blazor WebAssembly aplikacích, ale jenom napsáním vlastního kódu nebo použitím balíčku třetí strany.
Obecně platí, sessionStorage
že je bezpečnější používat.
sessionStorage
zabraňuje riziku, že uživatel otevře více karet a narazí na následující:
- Chyby ve stavové úložišti na kartách
- Matoucí chování při přepsání stavu jiných karet tabulátoru
localStorage
je lepší volbou, pokud aplikace musí zachovat stav při zavření a opětovném otevření prohlížeče.
Upozorňující
Uživatelé mohou zobrazit nebo manipulovat s daty uloženými v localStorage
a sessionStorage
.
Služba kontejneru stavu v paměti
Vnořené komponenty obvykle sváže data pomocí zřetězených vazeb, jak je popsáno v Blazor ASP.NET Core. Vnořené a nenestované komponenty můžou sdílet přístup k datům pomocí registrovaného kontejneru stavu v paměti. Třída kontejneru vlastního stavu může použít přiřaditelné Action k oznamování komponent v různých částech aplikace změn stavu. V následujícím příkladu:
- Dvojice komponent používá ke sledování vlastnosti kontejner stavu.
- Jedna komponenta v následujícím příkladu je vnořená do druhé komponenty, ale pro tento přístup není vyžadováno vnoření.
Důležité
Příklad v této části ukazuje, jak vytvořit službu kontejneru stavu v paměti, zaregistrovat službu a používat ji v komponentách. Příklad neuchovává data bez dalšího vývoje. V případě trvalého úložiště dat musí kontejner stavu přijmout základní mechanismus úložiště, který přežije, když se vymaže paměť prohlížeče. Toho lze dosáhnout pomocí localStorage
/sessionStorage
nebo jiné technologie.
StateContainer.cs
:
public class StateContainer
{
private string? savedString;
public string Property
{
get => savedString ?? string.Empty;
set
{
savedString = value;
NotifyStateChanged();
}
}
public event Action? OnChange;
private void NotifyStateChanged() => OnChange?.Invoke();
}
Klientské aplikace (Program
soubor):
builder.Services.AddSingleton<StateContainer>();
Serverové aplikace (Program
soubor, ASP.NET Core v .NET 6 nebo novější):
builder.Services.AddScoped<StateContainer>();
Serverové aplikace (Startup.ConfigureServices
z Startup.cs
, ASP.NET Core starší než 6.0):
services.AddScoped<StateContainer>();
Shared/Nested.razor
:
@implements IDisposable
@inject StateContainer StateContainer
<h2>Nested component</h2>
<p>Nested component Property: <b>@StateContainer.Property</b></p>
<p>
<button @onclick="ChangePropertyValue">
Change the Property from the Nested component
</button>
</p>
@code {
protected override void OnInitialized()
{
StateContainer.OnChange += StateHasChanged;
}
private void ChangePropertyValue()
{
StateContainer.Property =
$"New value set in the Nested component: {DateTime.Now}";
}
public void Dispose()
{
StateContainer.OnChange -= StateHasChanged;
}
}
StateContainerExample.razor
:
@page "/state-container-example"
@implements IDisposable
@inject StateContainer StateContainer
<h1>State Container Example component</h1>
<p>State Container component Property: <b>@StateContainer.Property</b></p>
<p>
<button @onclick="ChangePropertyValue">
Change the Property from the State Container Example component
</button>
</p>
<Nested />
@code {
protected override void OnInitialized()
{
StateContainer.OnChange += StateHasChanged;
}
private void ChangePropertyValue()
{
StateContainer.Property = "New value set in the State " +
$"Container Example component: {DateTime.Now}";
}
public void Dispose()
{
StateContainer.OnChange -= StateHasChanged;
}
}
Předchozí komponenty implementují IDisposablea OnChange
delegáti se odhlásí v Dispose
metodách, které jsou volány rozhraním při odstranění komponent. Další informace najdete v tématu Životní cyklus komponent ASP.NET Core Razor.
Další přístupy
Při implementaci vlastního úložiště stavu je užitečným přístupem přijmout kaskádové hodnoty a parametry:
- Pokud chcete využívat stav napříč mnoha komponentami.
- Pokud existuje jen jeden objekt stavu nejvyšší úrovně, který se má zachovat.
Odstraňování potíží
Pokud používáte vlastní službu správy stavu, ve které chcete podporovat úpravy stavu mimo kontext synchronizace Blazor(například z časovače nebo služby na pozadí), musí všechny komponenty, které využívají, obálit volání StateHasChanged do ComponentBase.InvokeAsync. Tím zajistíte, že se oznámení o změně zpracuje v kontextu synchronizace rendereru.
Pokud služba správy stavu nevolá StateHasChangedBlazorkontext synchronizace, vyvolá se následující chyba:
System.InvalidOperationException: Aktuální vlákno není přidruženo k Dispatcheru. Pomocí InvokeAsync() můžete při aktivaci vykreslování nebo stavu součásti přepnout spuštění na Dispečera.
Další informace a příklad řešení této chyby najdete v tématu Razor komponent Core.
Další materiály
- Uložení stavu aplikace před operací ověřování (Blazor WebAssembly)
- Správa stavu prostřednictvím rozhraní API externího serveru