Megosztás a következőn keresztül:


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á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 adat localStorage-ban megmarad, amíg kifejezetten nem kerül törlésre. A "privát böngészés" vagy "inkognitó" munkamenetbe betöltött dokumentumok localStorage 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 sessionStoragecé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ó

  1. 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.

  2. 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>
    
  3. A Startup.ConfigureServicesszám alatt hívja meg a AddProtectedBrowserStorage-t, hogy a localStorage és sessionStorage 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.SetAsynchaszná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 sessionStoragehelyre, é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 ProtectedBrowserStoragekezelé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á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ó:

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 adat localStorage-ban megmarad, amíg kifejezetten nem kerül törlésre. A "privát böngészés" vagy "inkognitó" munkamenetbe betöltött dokumentumok localStorage 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 sessionStoragetá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.csStartup.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