Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
U přechodných dat, která uživatel aktivně vytváří, je běžně používaným úložištěm kolekce prohlížeče localStorage a sessionStorage.
-
localStorageje omezen na úroveň 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 v prohlížeči, stav se sdílí mezi těmito kartami. Data přetrvávají vlocalStorage, dokud nejsou explicitně vymazána. DatalocalStoragepro dokument načtený v relaci "privátního procházení" nebo "anonymního režimu" se vymažou, jakmile je zavřena poslední soukromá karta. -
sessionStorageje omezený na kartu prohlížeče. Pokud uživatel kartu znovu načte, stávající stav se zachová. Když uživatel zavře kartu nebo prohlíž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 setká se s následujícím:
- Chyby v ukládání stavu napříč kartami
- Matoucí chování při přepsání stavu ostatních záložek
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 manipulovat. ASP.NET Základní ochrana dat může riziko zmírnit. Například ASP.NET Core Protected Browser Storage používá ASP.NET Core Data Protection.
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.
chráněné úložiště prohlížeče 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.
Výstraha
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.cshtmlDo souboru přidejte do koncové</body>značky následující skript:<script src="_content/Microsoft.AspNetCore.ProtectedBrowserStorage/protectedBrowserStorage.js"></script>V
Startup.ConfigureServiceszavolejteAddProtectedBrowserStoragepro přidánílocalStorageasessionStorageslužeb do sbírky 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:
ProtectedLocalStorageProtectedSessionStorage
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. Použití souboru _Imports.razor zpřístupňuje obor názvů větším segmentům aplikace nebo celé aplikaci.
Pokud chcete zachovat hodnotu currentCount v komponentě Counter aplikace na základě šablony projektu Blazor, upravte metodu IncrementCount tak, aby používala ProtectedSessionStore.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ě situace, kdy je uživatel na 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ýsledek v null, nikoli v OnParametersSetAsync.
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.
Výstraha
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ý pracuje s předrenderingem, najdete v sekci Zvládání předrenderingu.
Řešení 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í, vždy existuje doba, než jsou data načtena a zpřístupněna 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 nulldata , což znamená, že se data stále načítají. Ve výchozí Counter komponentě se počet nachází v objektu int.
Udělat currentCount volitelným přidáním otazníku (?) k typu (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ředrenderování
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)" />
Další informace naleznete v tématu Prerender ASP.NET Core Razor komponenty.
Chcete-li zakázat předběžné vykreslování, otevřete _Host.cshtml soubor a změňte render-mode atribut Component Tag Helper na Server:
<component type="typeof(App)" render-mode="Server" />
Pokud je předpočítání zakázané, je předpočítá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 uchování stavu.
V následujícím příkladu komponenty CounterStateProvider se data čítače uchovávají v sessionStoragea 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 RenderFragment naleznete v komponentech Razor ASP.NET Core.
Pokud chcete, aby byl stav přístupný pro všechny komponenty v aplikaci, zabalte komponentu CounterStateProvider kolem komponenty Router (<Router>...</Router>) s použitím globálního interaktivního vykreslování na straně serveru (Routes 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 .NET 5.0.1 a pro všechny další verze 5.x komponenta Router obsahuje parametr PreferExactMatches nastaven na @true. Další informace najdete v tématu Migrace z ASP.NET Core 3.1 na .NET 5.
Zabalené komponenty přijímají a mohou pozměnit uložený 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 s ProtectedBrowserStorage ani se nezabývá fází "načítání".
Obecně se doporučuje vzor komponenty nadřazené poskytovatele 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žiny objektů na různých místech, je lepší se vyhnout globálnímu ukládání stavu.