ASP.NET Core Blazor állapotkezelése
Jegyzet
Ez nem a cikk legújabb verziója. Az aktuális kiadást lásd a jelen cikk .NET 9-es verziójában,.
Figyelmeztetés
A ASP.NET Core ezen verziója már nem támogatott. További információ: .NET és .NET Core támogatási szabályzat. Az aktuális kiadást lásd a jelen cikk .NET 9-es verziójában,.
Fontos
Ezek az információk egy olyan előzetes termékre vonatkoznak, amelyet a kereskedelmi forgalomba kerülés előtt jelentősen módosíthatnak. A Microsoft nem vállal kifejezett vagy hallgatólagos szavatosságot az itt megadott információkra vonatkozóan.
Az aktuális kiadást lásd a jelen cikk .NET 9-es verziójában,.
Ez a cikk a felhasználók adatainak (állapotának) az alkalmazás használata során és a böngésző munkamenetekben való fenntartásának gyakori megközelítéseit ismerteti.
Jegyzet
A cikkben szereplő példakódok null értékű referenciatípusokat (NRT-ket) és .NET-fordító nullállapotú statikus elemzésivezetnek be, amelyeket a .NET 6-os vagy újabb verziójú ASP.NET Core támogat. Ha ASP.NET Core 5.0-s vagy korábbi verziójára céloz, távolítsa el a null típusú megjelölést (?
) a cikk példáiban szereplő típusok közül.
Felhasználói állapot karbantartása
A kiszolgálóoldali Blazor állapotalapú alkalmazás-keretrendszer. Az alkalmazás legtöbbször kapcsolatot tart fenn a kiszolgálóval. A felhasználó állapota a kiszolgáló memóriájában van egy áramkörben.
Példák az áramkörben tárolt felhasználói állapotra:
- Az összetevőpéldányok hierarchiája és legutóbbi renderelési kimenete a renderelt felhasználói felületen.
- Az összetevőpéldányok mezőinek és tulajdonságainak értékei.
- A függőséginjektálási (DI) szolgáltatáspéldányokban tárolt adatok, amelyek hatóköre a környezetre terjed ki.
Előfordulhat, hogy a felhasználó állapota javaScript-változókban is megtalálható a böngésző memóriakészletében JavaScript interop hívásokon keresztül.
Ha egy felhasználó átmeneti hálózati kapcsolatvesztést tapasztal, Blazor megpróbálja újra csatlakoztatni a felhasználót az eredeti kapcsolatcsoporthoz az eredeti állapotával. Azonban a felhasználó újracsatlakoztatása az eredeti kapcsolatcsoporthoz a kiszolgáló memóriájában nem mindig lehetséges:
- A kiszolgáló nem tudja örökre megőrizni a leválasztott kapcsolatot. A kiszolgálónak időtúllépés után vagy memóriaterhelés esetén fel kell szabadítania a leválasztott áramkört.
- Többkiszolgálós, elosztott terhelésű üzembehelyezési környezetekben előfordulhat, hogy az egyes kiszolgálók sikertelenek vagy automatikusan el lesznek távolítva, ha már nincs szükség a kérelmek teljes mennyiségének kezelésére. A felhasználó eredeti kiszolgálófeldolgozási kérelmei elérhetetlenné válhatnak, amikor a felhasználó újracsatlakozik.
- A felhasználó bezárhatja és újra megnyithatja a böngészőt, vagy újra betöltheti a lapot, ami eltávolítja a böngésző memóriájában tárolt állapotokat. A JavaScript interop-hívásokon beállított JavaScript-változóértékek például elvesznek.
Ha egy felhasználó nem csatlakoztatható újra az eredeti kapcsolatcsoporthoz, a felhasználó egy üres állapotú új kapcsolatcsoportot kap. Ez egyenértékű egy asztali alkalmazás bezárásával és újbóli megnyitásával.
Állapot megőrzése az áramkörök között
Az állapotot általában olyan áramkörök esetén tartsuk fenn, amelyeknél a felhasználók aktívan hoznak létre adatokat, és nem csupán a már létező adatokat olvassák.
A kapcsolatcsoportok állapotának megőrzéséhez az alkalmazásnak a kiszolgáló memóriáján kívül más tárolási helyre kell megőriznie az adatokat. Az állapotmegőrzés nem automatikus. Az állapotalapú adatmegőrzés megvalósításához lépéseket kell tennie az alkalmazás fejlesztésekor.
Az adatmegőrzés általában csak azokhoz a nagy értékű állapotokhoz szükséges, amelyeket a felhasználók igyekeztek létrehozni. A következő példákban a tartós állapot időt takarít meg, vagy segít a kereskedelmi tevékenységekben:
- Többlépéses webes űrlapok: A többlépéses webes űrlapok több lépésből álló lépéseinek adatainak újbóli bevitele időigényes, ha az állapotuk elveszik. A felhasználók elveszítik az állapotukat ebben a forgatókönyvben, ha eltávolodnak az űrlaptól, és később térnek vissza.
- Bevásárlókocsik: Az alkalmazás minden olyan üzletileg fontos összetevője, amely a potenciális bevételt képviseli, fenntartható. Azok a felhasználók, akik elveszítik az állapotukat, így a bevásárlókocsijukat, kevesebb terméket vagy szolgáltatást vásárolhatnak, amikor később visszatérnek a webhelyre.
Egy alkalmazás csak alkalmazásállapot-őrizhet meg. A felhasználói felületek nem tartósíthatók, például az összetevők példányai és a renderelési fák. Az összetevők és a renderfák általában nem szerializálhatók. A felhasználói felület állapotának (például egy fanézet vezérlőelem kibontott csomópontjainak) megőrzéséhez az alkalmazásnak egyéni kóddal kell modelleznie a felhasználói felület állapotának viselkedését szerializálható alkalmazásállapotként.
Hol tároljuk az állapotot
Vannak közös helyek az állapot megőrzésére:
- kiszolgálóoldali tároló
- URL
- Böngészőtároló
- memóriabeli állapotú tárolószolgáltatás
- kaszkádolt értékek és paraméterek
Kiszolgálóoldali tárolás
A több felhasználóra és eszközre kiterjedő állandó adatmegőrzés érdekében az alkalmazás kiszolgálóoldali tárolást használhat. A lehetőségek a következők:
- Blobtároló
- Kulcs-érték tároló
- Relációs adatbázis
- Táblatároló
Az adatok mentése után a felhasználó állapota megmarad, és bármely új kapcsolatcsoportban elérhető.
Az Azure-beli adattárolási lehetőségekről az alábbiakban talál további információt:
URL-cím
A navigációs állapotot jelképező átmeneti adatok esetében modellezi az adatokat az URL-cím részeként. Példák az URL-címben modellezett felhasználói állapotra:
- Egy megtekintett entitás azonosítója.
- A lapozott rács aktuális oldalszáma.
A böngésző címsorának tartalma megmarad:
- Ha a felhasználó manuálisan újra betölti a lapot.
- Ha a webkiszolgáló elérhetetlenné válik, és a felhasználónak újra kell betöltenie a lapot egy másik kiszolgálóhoz való csatlakozáshoz.
Az URL-minták @page
irányelvvel való meghatározásáról további információt a ASP.NET Core Blazor útválasztási és navigációscímű cikkben talál.
Böngésző tárterülete
A felhasználó által aktívan létrehozott átmeneti adatok esetében a gyakran használt tárolóhely a böngésző localStorage
és sessionStorage
gyűjteménye:
-
localStorage
hatóköre a böngésző adott példányára terjed ki. Ha a felhasználó újra betölti a lapot, vagy bezárja és újra megnyitja a böngészőt, az állapot megmarad. Ha a felhasználó több böngészőlapot nyit meg, az állapot meg van osztva a lapok között. Az adatlocalStorage
-ban megmarad, amíg kifejezetten nem kerül törlésre. A "privát böngészés" vagy "inkognitó" munkamenetbe betöltött dokumentumoklocalStorage
adatai törlődnek az utolsó "privát" lap bezárásakor. -
sessionStorage
hatóköre a böngészőlapra terjed ki. Ha a felhasználó újra betölti a lapot, az állapot megmarad. Ha a felhasználó bezárja a lapot vagy a böngészőt, az állapot elveszik. Ha a felhasználó több böngészőlapot nyit meg, mindegyik lap saját, független adatverzióval rendelkezik.
Általában a sessionStorage
használata biztonságosabb.
sessionStorage
elkerüli annak kockázatát, hogy egy felhasználó több lapot nyit meg, és a következőkkel találkozik:
- A lapok közötti állapottárolóban lévő hibák.
- Zavaró jelenség, amikor egy lap felülírja a többi lap állapotát.
localStorage
a jobb választás, ha az alkalmazásnak meg kell őriznie az állapotot a böngésző bezárásakor és újbóli megnyitásakor.
A böngészőtároló használatának kikötései:
- A kiszolgálóoldali adatbázisokhoz hasonlóan az adatok betöltése és mentése aszinkron.
- A kért lap nem létezik a böngészőben az előrendelés során, ezért a helyi tárterület nem érhető el az előrendelés során.
- A kiszolgálóoldali Blazor-alkalmazások esetében ésszerű néhány kilobájtnyi adat tárolása. Néhány kilobájton túl figyelembe kell vennie a teljesítményre gyakorolt hatásokat, mivel az adatok betöltése és mentése a hálózaton keresztül történik.
- A felhasználók megtekinthetik vagy módosíthatják az adatokat. ASP.NET Core Data Protection csökkentheti a kockázatot. Például ASP.NET Core Protected Browser Storage ASP.NET Core Data Protectiont használ.
Harmadik fél által készített NuGet-csomagok API-kat biztosítanak localStorage
és sessionStorage
. Érdemes megfontolni egy olyan csomag kiválasztását, amely transzparens módon használja ASP.NET Core Data Protection. A Data Protection titkosítja a tárolt adatokat, és csökkenti a tárolt adatok illetéktelen hozzáférésének kockázatát. Ha a JSON-szerializált adatok egyszerű szövegben vannak tárolva, a felhasználók böngészőfejlesztői eszközökkel láthatják az adatokat, és módosíthatják a tárolt adatokat is. A triviális adatok biztonságossá tétele nem jelent problémát. A felhasználói felület elemeinek tárolt színének olvasása vagy módosítása például nem jelent jelentős biztonsági kockázatot a felhasználóra vagy a szervezetre nézve. Kerülje el, hogy a felhasználók megvizsgálhassák vagy illetéktelenül beavatkozhassanak a bizalmas adatokba .
ASP.NET Core védett böngészőalapú tároló
ASP.NET Core Protected Browser Storage az ASP.NET Core Data Protection használja localStorage
és sessionStorage
céljából.
Jegyzet
A Védett böngészőtár a ASP.NET Core Data Protectionre támaszkodik, és csak a kiszolgálóoldali Blazor alkalmazások esetében támogatott.
Figyelmeztetés
Microsoft.AspNetCore.ProtectedBrowserStorage
egy nem támogatott, kísérleti csomag, amely nem éles használatra készült.
A csomag csak ASP.NET Core 3.1-alkalmazásokban használható.
Konfiguráció
Adj hozzá egy csomaghivatkozást a
Microsoft.AspNetCore.ProtectedBrowserStorage
-hoz.Jegyzet
A csomagok .NET-alkalmazásokhoz való hozzáadásáról a Csomagok telepítése és kezeléseCsomaghasználati munkafolyamat (NuGet-dokumentáció)című cikkben talál útmutatást. Ellenőrizze a megfelelő csomagverziókat a NuGet.org.
A
_Host.cshtml
fájlban adja hozzá a következő szkriptet a záró</body>
címkéhez:<script src="_content/Microsoft.AspNetCore.ProtectedBrowserStorage/protectedBrowserStorage.js"></script>
A
Startup.ConfigureServices
szám alatt hívja meg aAddProtectedBrowserStorage
-t, hogy alocalStorage
éssessionStorage
szolgáltatásokat hozzáadja a szolgáltatásgyűjteményhez.services.AddProtectedBrowserStorage();
Adatok mentése és betöltése egy összetevőn belül
Az adatok böngészőtárolóba való betöltését vagy mentését igénylő összetevőkben a @inject
direktívával szúrja be az alábbiak valamelyikének egy példányát:
ProtectedLocalStorage
ProtectedSessionStorage
A választás attól függ, hogy melyik böngészőtárhelyet szeretné használni. A következő példában a sessionStorage
használjuk:
@using Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage
@inject ProtectedSessionStorage ProtectedSessionStore
@using Microsoft.AspNetCore.ProtectedBrowserStorage
@inject ProtectedSessionStorage ProtectedSessionStore
A @using
irányelv az összetevő helyett az alkalmazás _Imports.razor
fájljába helyezhető. A _Imports.razor
fájl használata elérhetővé teszi a névteret az alkalmazás vagy az egész alkalmazás nagyobb szegmensei számára.
Ha meg szeretné őrizni a currentCount
értéket egy alkalmazás Counter
összetevőjében a Blazor projektsablonalapján, módosítsa a IncrementCount
metódust a ProtectedSessionStore.SetAsync
használatára:
private async Task IncrementCount()
{
currentCount++;
await ProtectedSessionStore.SetAsync("count", currentCount);
}
A nagyobb, valósághűbb alkalmazásokban az egyes mezők tárolása nem valószínű. Az alkalmazások nagyobb valószínűséggel teljes modellobjektumokat tárolnak, amelyek összetett állapotot tartalmaznak.
ProtectedSessionStore
automatikusan szerializálja és deszerializálja a JSON-adatokat összetett állapotobjektumok tárolásához.
Az előző kódpéldában a currentCount
adatokat sessionStorage['count']
-ként tárolják a felhasználó böngészőjében. Az adatok nem egyszerű szövegben tárolódnak, hanem ASP.NET Core Data Protection használatával védettek. A titkosított adatok megvizsgálhatók, ha sessionStorage['count']
kiértékelése a böngésző fejlesztői konzolján történik.
A currentCount
adatok helyreállításához, ha a felhasználó később visszatér a Counter
összetevőhöz, beleértve azt is, hogy a felhasználó új kapcsolatcsoportban van-e, használja a 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");
}
Ha a navigációs állapot belefoglaltatik az összetevő paramétereibe, hívja meg a ProtectedSessionStore.GetAsync
-t, és rendeljen hozzá egynull
-től eltérő eredményt OnParametersSetAsync-höz, nem pedig OnInitializedAsync-hoz.
OnInitializedAsync csak egyszer lesz meghívva az összetevő első példányosításakor.
OnInitializedAsync később nem lesz újra meghívva, ha a felhasználó egy másik URL-címre navigál, miközben ugyanazon az oldalon marad. További információ: ASP.NET Core Razor-összetevők életciklusa.
Figyelmeztetés
Az ebben a szakaszban szereplő példák csak akkor működnek, ha a kiszolgálón nincs engedélyezve az előrenderelés. Ha engedélyezve van az előrendelés, hibaüzenet jelenik meg, amely azt magyarázza, hogy a JavaScript interop-hívások nem adhatók ki, mert az összetevőt előrerendelték.
Tiltsa le az előrendelést, vagy adjon hozzá további kódot az előrendelés használatához. Az előrerendereléssel való kódírás részleteiről a Előrerenderelés kezelése szakaszban olvashat bővebben.
A betöltési állapot kezelése
Mivel a böngésző tárterülete aszinkron módon érhető el egy hálózati kapcsolaton keresztül, az adatok betöltése előtt mindig van egy időszak, amely egy összetevő számára elérhetővé válik. A legjobb eredmény érdekében az üres vagy alapértelmezett adatok megjelenítése helyett a betöltés közben jelenítsen meg egy üzenetet.
Az egyik módszer az, hogy ellenőrizzük, az adatok null
állapotban vannak-e, ami azt jelenti, hogy az adatok betöltése még folyamatban van. Az alapértelmezett Counter
összetevőben a darabszám egy int
-ben van tárolva.
currentCount
null értékű létrehozása kérdőjel (?
) hozzáadásával a típushoz (int
):
private int? currentCount;
A darabszám és a Increment
gomb feltétel nélküli megjelenítése helyett csak akkor jelenítse meg ezeket az elemeket, ha az adatok betöltése sikeresen ellenőrizve van HasValuealapján:
@if (currentCount.HasValue)
{
<p>Current count: <strong>@currentCount</strong></p>
<button @onclick="IncrementCount">Increment</button>
}
else
{
<p>Loading...</p>
}
Prerenderelés kezelése
Az előrenderelés során:
- Nem létezik interaktív kapcsolat a felhasználó böngészőjével.
- A böngésző még nem rendelkezik olyan laplal, amelyen futtathat JavaScript-kódot.
localStorage
vagy sessionStorage
nem érhetők el az előrendelés során. Ha az összetevő megpróbálja kezelni a tárterületet, hibaüzenet jelenik meg, amely azt jelzi, hogy a JavaScript interop-hívások nem adhatók ki, mert az összetevőt előrerendelték.
A hiba megoldásának egyik módja az előzetes rendezés letiltása. Ez általában akkor a legjobb választás, ha az alkalmazás gyakran használja a böngészőalapú tárhelyet. Az előrendelés összetettebbé teszi az alkalmazást, és nem jár előnyökkel, mivel az alkalmazás nem tud előrendelni semmilyen hasznos tartalmat, amíg el nem érhető localStorage
vagy sessionStorage
.
Az előzetes renderelés letiltásához az alkalmazás összetevőhierarchiájának legmagasabb szintű, nem gyökérösszetevőjénél jelezze a renderelési módot az prerender
paraméter false
-értékre állításával.
Jegyzet
A gyökérösszetevő interaktívvá tétele, például a App
összetevő nem támogatott. Ezért a App
összetevő nem tilthatja le közvetlenül az előzetes rendezést.
A Blazor Web App projektsablonon alapuló alkalmazások esetében a prerenderelés jellemzően le van tiltva, ahol a Routes
összetevő a App
összetevőt használja (Components/App.razor
).
<Routes @rendermode="new InteractiveServerRenderMode(prerender: false)" />
Emellett tiltsa le az előrenderelést a HeadOutlet
összetevőhöz:
<HeadOutlet @rendermode="new InteractiveServerRenderMode(prerender: false)" />
További információ: ASP.NET Core Blazor renderelési módok.
Az előzetes betöltés letiltásához nyissa meg a _Host.cshtml
fájlt, és módosítsa a render-mode
attribútumát Server-re.
<component type="typeof(App)" render-mode="Server" />
Ha az előrenderelés le van tiltva, akkor a <head>
tartalom előrenderelése is le van tiltva.
Az előrendezés hasznos lehet azoknál a lapoknál is, amelyek nem használnak localStorage
vagy sessionStorage
. Az előrendelés megőrzéséhez halasztsa a betöltési műveletet, amíg a böngésző nem csatlakozik a kapcsolatcsoporthoz. Az alábbi példa egy számlálóérték tárolására használható:
@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);
}
}
Az állapot megőrzésének kiemelése egy közös szolgáltatóhoz
Ha sok összetevő böngészőalapú tárolásra támaszkodik, az állapotszolgáltatói kód megvalósítása sokszor létrehozza a kód duplikálását. A kódismétlés elkerülésének egyik lehetősége egy állapotszolgáltató szülőösszetevőjének létrehozása, amely magában foglalja az állapotszolgáltató logikáját. A gyermekösszetevők az állapotmegőrzési mechanizmustól függetlenül dolgozhatnak a tárolt adatokkal.
Egy CounterStateProvider
összetevő alábbi példájában a számlálóadatok elmentődnek sessionStorage
helyre, és úgy kezeli a betöltési fázist, hogy nem jeleníti meg a gyermektartalmat, amíg az állapot teljesen be nem töltődik.
A CounterStateProvider
összetevő az előrenderelést úgy kezeli, hogy csak az állapotot a komponens renderelése után tölti be a OnAfterRenderAsync
életciklus-metódusban, amely nem hajtódik végre előrenderelés közben.
Az ebben a szakaszban ismertetett megközelítés nem képes több előfizetett összetevő újrarendezésének aktiválására ugyanazon az oldalon. Ha egy előfizetett összetevő módosítja az állapotot, az újrarendezi és megjelenítheti a frissített állapotot, de ugyanazon az oldalon egy másik összetevő jelenik meg, amely az elavult adatokat jeleníti meg a saját következő rerenderéig. Ezért az ebben a szakaszban ismertetett megközelítés a legjobban alkalmas az állapotnak a lap egyetlen összetevőjében való használatára.
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);
}
}
Jegyzet
A RenderFragmenttovábbi információkért lásd ASP.NET Core Razor összetevőit.
Ha elérhetővé szeretné tenni az állapotot egy alkalmazás összes összetevője számára, csomagolja a Router (<Router>...</Router>
) CounterStateProvider
összetevőt a Routes
összetevőbe globális interaktív kiszolgálóoldali rendereléssel (interaktív SSR).
A App
összetevőben (Components/App.razor
):
<Routes @rendermode="InteractiveServer" />
A Routes
összetevőben (Components/Routes.razor
):
A CounterStateProvider
összetevő használatához burkolja az összetevő egy példányát bármely más összetevő köré, amely hozzáférést igényel a számláló állapotához. Ha elérhetővé szeretné tenni az állapotot egy alkalmazás összes összetevője számára, csomagolja be a CounterStateProvider
összetevőt a Router a App
összetevőbe (App.razor
):
<CounterStateProvider>
<Router ...>
...
</Router>
</CounterStateProvider>
Jegyzet
A ASP.NET Core 5.0.1 kiadásával és minden további 5.x kiadás esetén a Router
összetevő tartalmazza a PreferExactMatches
paramétert @true
. További információért lásd: Migráljon az ASP.NET Core 3.1-ről 5.0-ra.
A burkolt komponensek fogadják és módosíthatják a megőrzött számláló állapotát. A következő Counter
összetevő implementálja a mintát:
@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();
}
}
}
Az előző összetevő nem szükséges a ProtectedBrowserStorage
kezeléséhez, és nem vesz részt a "betöltési" fázisban sem.
Általában az állapotszolgáltató szülő komponens mintája,, ajánlott.
- Az állapot több komponensen keresztüli felhasználása.
- Ha csak egy legfelső szintű állapotobjektumot szeretne megőrzeni.
A különböző állapotobjektumok megőrzéséhez és az objektumok különböző részhalmazainak különböző helyeken való felhasználásához érdemes elkerülni az állapot globális megőrzését.
A Blazor WebAssembly alkalmazásban létrehozott felhasználói állapot a böngésző memóriájában található.
Példák a böngészőmemóriában tárolt felhasználói állapotra:
- Az összetevőpéldányok hierarchiája és legutóbbi renderelési kimenete a renderelt felhasználói felületen.
- Az összetevőpéldányok mezőinek és tulajdonságainak értékei.
- Az adatok függőséginjektálás (DI) szolgáltatáspéldányokban tárolódnak.
- A JavaScript interop hívásokon keresztül beállított értékek.
Amikor egy felhasználó bezárja és újra megnyitja a böngészőt, vagy újra betölti a lapot, a böngésző memóriájában tárolt felhasználói állapot elveszik.
Jegyzet
Védett böngészőtár (Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage névtér) az ASP.NET Core Data Protectionre támaszkodik, és csak kiszolgálóoldali Blazor-alkalmazások esetében támogatott.
Állapot megőrzése böngésző-munkamenetekben
Általában tartsuk fenn a böngésző munkamenetek állapotát, ha a felhasználók aktívan hoznak létre adatokat, nem pedig csupán a már létező adatokat olvassák.
Az állapot böngésző-munkamenetek közötti megőrzéséhez az alkalmazásnak a böngésző memóriáján kívül más tárolási helyre kell megőriznie az adatokat. Az állapotmegőrzés nem automatikus. Az állapotalapú adatmegőrzés megvalósításához lépéseket kell tennie az alkalmazás fejlesztésekor.
Az adatmegőrzés általában csak azokhoz a nagy értékű állapotokhoz szükséges, amelyeket a felhasználók igyekeztek létrehozni. A következő példákban a tartós állapot időt takarít meg, vagy segít a kereskedelmi tevékenységekben:
- Többlépéses webes űrlapok: A többlépéses webes űrlapok több lépésből álló lépéseinek adatainak újbóli bevitele időigényes, ha az állapotuk elveszik. A felhasználók elveszítik az állapotukat ebben a forgatókönyvben, ha eltávolodnak az űrlaptól, és később térnek vissza.
- Bevásárlókocsik: Az alkalmazás minden olyan üzletileg fontos összetevője, amely a potenciális bevételt képviseli, fenntartható. Azok a felhasználók, akik elveszítik az állapotukat, így a bevásárlókocsijukat, kevesebb terméket vagy szolgáltatást vásárolhatnak, amikor később visszatérnek a webhelyre.
Egy alkalmazás csak alkalmazásállapot-őrizhet meg. A felhasználói felületek nem tartósíthatók, például az összetevők példányai és a renderelési fák. Az összetevők és a renderfák általában nem szerializálhatók. A felhasználói felület állapotának (például egy fanézet vezérlőelem kibontott csomópontjainak) megőrzéséhez az alkalmazásnak egyéni kóddal kell modelleznie a felhasználói felület állapotának viselkedését szerializálható alkalmazásállapotként.
Hol tároljuk az állapotot
Vannak közös helyek az állapot megőrzésére:
- kiszolgálóoldali tároló
- URL
- Böngészőtároló
- memóriabeli állapotú tárolószolgáltatás
- kaszkádolt értékek és paraméterek
Kiszolgálóoldali tárolás
A több felhasználóra és eszközre kiterjedő állandó adatmegőrzés érdekében az alkalmazás használhat független kiszolgálóoldali tárolót, amely egy webes API-val érhető el. A lehetőségek a következők:
- Blobtároló
- Kulcs-érték tároló
- Relációs adatbázis
- Táblatároló
Az adatok mentése után a felhasználó állapota megmarad, és minden új böngésző-munkamenetben elérhető.
Mivel Blazor WebAssembly alkalmazások teljes mértékben a felhasználó böngészőjében futnak, további intézkedéseket igényelnek a biztonságos külső rendszerek, például a tárolási szolgáltatások és az adatbázisok eléréséhez. Blazor WebAssembly alkalmazásokat ugyanúgy védik, mint az egyoldalas alkalmazásokat (SLA-k). Az alkalmazások általában OAuth/OpenID Connect (OIDC) keresztül hitelesítik a felhasználókat, majd a kiszolgálóoldali alkalmazások webes API-hívásain keresztül kommunikálnak a tárolási szolgáltatásokkal és az adatbázisokkal. A kiszolgálóoldali alkalmazás közvetíti az adatok átvitelét a Blazor WebAssembly alkalmazás és a tárolási szolgáltatás vagy adatbázis között. A Blazor WebAssembly alkalmazás rövid ideig tartó kapcsolatot tart fenn a kiszolgálóoldali alkalmazással, míg a kiszolgálóoldali alkalmazás állandó kapcsolatot létesít a tárolóval.
További információ:
- Webes API meghívása egy ASP.NET Core Blazor-alkalmazásból
- Biztonságos ASP.NET Core Blazor WebAssembly
- Blazor biztonsági és Identity cikkek
Az Azure-beli adattárolási lehetőségekről az alábbiakban talál további információt:
URL-cím
A navigációs állapotot jelképező átmeneti adatok esetében modellezi az adatokat az URL-cím részeként. Példák az URL-címben modellezett felhasználói állapotra:
- Egy megtekintett entitás azonosítója.
- A lapozott rács aktuális oldalszáma.
A böngésző címsorának tartalma megmarad, ha a felhasználó manuálisan újra betölti az oldalt.
Az URL-minták @page
irányelvvel való meghatározásáról további információt a ASP.NET Core Blazor útválasztási és navigációscímű cikkben talál.
Böngésző tárterülete
A felhasználó által aktívan létrehozott átmeneti adatok esetében a gyakran használt tárolóhely a böngésző localStorage
és sessionStorage
gyűjteménye:
-
localStorage
hatóköre a böngésző adott példányára terjed ki. Ha a felhasználó újra betölti a lapot, vagy bezárja és újra megnyitja a böngészőt, az állapot megmarad. Ha a felhasználó több böngészőlapot nyit meg, az állapot meg van osztva a lapok között. Az adatlocalStorage
-ban megmarad, amíg kifejezetten nem kerül törlésre. A "privát böngészés" vagy "inkognitó" munkamenetbe betöltött dokumentumoklocalStorage
adatai törlődnek az utolsó "privát" lap bezárásakor. -
sessionStorage
hatóköre a böngészőlapra terjed ki. Ha a felhasználó újra betölti a lapot, az állapot megmarad. Ha a felhasználó bezárja a lapot vagy a böngészőt, az állapot elveszik. Ha a felhasználó több böngészőlapot nyit meg, mindegyik lap saját, független adatverzióval rendelkezik.
Jegyzet
localStorage
és sessionStorage
használható Blazor WebAssembly alkalmazásokban, de csak egyéni kód írásával vagy külső csomag használatával.
Általában a sessionStorage
használata biztonságosabb.
sessionStorage
elkerüli annak kockázatát, hogy egy felhasználó több lapot nyit meg, és a következőkkel találkozik:
- A lapok közötti állapottárolóban lévő hibák.
- Zavaró viselkedés, ha egy lap felülírja a többi lap állapotát.
localStorage
a jobb választás, ha az alkalmazásnak meg kell őriznie az állapotot a böngésző bezárásakor és újbóli megnyitásakor.
Figyelmeztetés
A felhasználók megtekinthetik vagy módosíthatják a localStorage
és sessionStorage
tárolt adatokat.
Memóriabeli állapotú tárolószolgáltatás
A beágyazott összetevők általában a láncolt kötés használatával kötik össze az adatokat az ASP.NET Core Blazor adatkötésileírása szerint. A beágyazott és a nem beágyazott összetevők megoszthatják az adatokhoz való hozzáférést egy regisztrált memóriabeli állapottároló használatával. Az egyéni állapottároló-osztály hozzárendelhető Action használatával értesítheti az alkalmazás különböző részeiben lévő összetevőket az állapotváltozásokról. Az alábbi példában:
- Egy összetevőpár állapottárolót használ egy tulajdonság nyomon követéséhez.
- Az alábbi példában szereplő egyik összetevő beágyazva van a másik összetevőbe, de a beágyazás nem szükséges a megközelítés működéséhez.
Fontos
Az ebben a szakaszban szereplő példa bemutatja, hogyan hozhat létre memóriabeli állapotú tárolószolgáltatást, regisztrálhatja a szolgáltatást, és hogyan használhatja a szolgáltatást az összetevőkben. A példa nem őriz meg adatokat további fejlesztés nélkül. Az állandó adattároláshoz az állapottárolónak olyan mögöttes tárolási mechanizmust kell alkalmaznia, amely a böngészőmemória törlésekor is megmarad. Ez localStorage
/sessionStorage
vagy más technológiával is elvégezhető.
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();
}
Ügyféloldali alkalmazások (Program
fájl):
builder.Services.AddSingleton<StateContainer>();
Kiszolgálóoldali alkalmazások (Program
fájl, ASP.NET Core a .NET 6-os vagy újabb verziójában):
builder.Services.AddScoped<StateContainer>();
Kiszolgálóoldali alkalmazások ( Startup.cs
Startup.ConfigureServices
, ASP.NET Core 6.0-nál korábbi):
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;
}
}
Az előző összetevők implementálják a IDisposable, és a OnChange
delegáltak leiratkoztatva vannak a Dispose
metódusokban, amelyeket a keretrendszer hív meg az összetevők megsemmisítésekor. További információért lásd: ASP.NET Core Razor összetevők eltávolítása.
Kaszkádolt értékek és paraméterek
kaszkádolt értékeket és paramétereket az állapot kezeléséhez használhatja úgy, hogy adatokat áramoltat egy előd komponensből Razor a leszármazott komponensekhez.
A legfelső szintű kaszkádolt értékek CascadingValueSource<TValue> lehetővé teszik, hogy a Razor komponens értesítéseket kapjon a megváltozott kaszkádolt értékekről. További információért és egy működő példáért, lásd a NotifyingDalek
példát a ASP.NET Core Blazor kaszkádolt értékek és paraméterek.
További megközelítések
Az egyéni állapottárolás megvalósításának egy hasznos megközelítése az, hogy alkalmazzuk a kaszkádolt értékeket és paramétereket.
- Az állapot több komponensen keresztüli felhasználása.
- Ha csak egy legfelső szintű állapotobjektumot szeretne megőrzeni.
Hibaelhárítás
Ha olyan egyéni állapotkezelési szolgáltatást használ, amely Blazorszinkronizálási környezetén kívülről (például időzítőből vagy háttérszolgáltatásból) szeretné támogatni az állapotmódosításokat, az összes fogyasztó összetevőnek be kell csomagolnia a StateHasChanged hívást ComponentBase.InvokeAsync. Ez biztosítja, hogy a változásértesítés a renderelő szinkronizálási környezetében legyen kezelve.
Ha az állapotfelügyeleti szolgáltatás nem hívja meg StateHasChangedBlazorszinkronizálási környezetében, a következő hibaüzenet jelenik meg:
System.InvalidOperationException: "Az aktuális szál nincs társítva a diszpécserrel. Az InvokeAsync() használatával állítsa át a végrehajtást a Dispatcheren, amikor a renderelést vagy az összetevő állapotát aktiválja.
További információkért és arra vonatkozó példáért, hogyan lehet elhárítani ezt a hibát, lásd: ASP.NET Core Razor összetevő renderelése.
További erőforrások
- Alkalmazásállapot mentése hitelesítési művelet (Blazor WebAssembly) előtt
- Állapot kezelése külső kiszolgálói API-val