Anteckning
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Utan kvarstående komponenttillstånd går tillståndet som används under förinläsningen förlorat och måste återskapas när appen är helt inläst. Om något tillstånd skapas asynkront kan användargränssnittet flimra när det förinstallerade användargränssnittet ersätts när komponenten återställs.
Överväg följande PrerenderedCounter1 räknarkomponent. Komponenten anger ett initialt slumpmässigt räknarvärde under förinläsning i OnInitialized livscykelmetoden. När komponenten sedan renderas interaktivt ersätts det inledande antalsvärdet när OnInitialized det körs en andra gång.
              PrerenderedCounter1.razor:
@page "/prerendered-counter-1"
@inject ILogger<PrerenderedCounter1> Logger
<PageTitle>Prerendered Counter 1</PageTitle>
<h1>Prerendered Counter 1</h1>
<p role="status">Current count: @currentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@code {
    private int currentCount;
    protected override void OnInitialized()
    {
        currentCount = Random.Shared.Next(100);
        Logger.LogInformation("currentCount set to {Count}", currentCount);
    }
    private void IncrementCount() => currentCount++;
}
Anmärkning
Om appen använder interaktiv routning och sidan nås via en intern förbättrad navigering sker inte prerendering. Därför måste du utföra en fullständig sidåterläsning för PrerenderedCounter1-komponenten för att se följande resultat. Mer information finns i avsnittet Interaktiv routning och prerendering .
Kör appen och inspektera loggning från komponenten. Följande är exempelutdata.
info: BlazorSample.Components.Pages.PrerenderedCounter1[0]
currentCount set to 41
info: BlazorSample.Components.Pages.PrerenderedCounter1[0]
currentCount set to 92
Det första loggade antalet inträffar under förhandsrendering. Antalet anges igen efter prerendering när komponenten har återskapats. Det finns också ett flimmer i användargränssnittet när antalet uppdateras från 41 till 92.
För att behålla räknarens initiala värde under förpresentationen stöder Blazor beständighet av tillstånd på en förrenderad sida med hjälp av PersistentComponentState-tjänsten (och för komponenter som är inbäddade i sidor eller vyer av Razor Pages- eller MVC-appar, Persist Component State Tag Helper).
Genom att initiera komponenter med samma tillstånd som används under förinläsningen körs eventuella dyra initieringssteg bara en gång. Det renderade användargränssnittet matchar också det förinstallerade användargränssnittet, så inget flimmer förekommer i webbläsaren.
Det beständiga förinstallerade tillståndet överförs till klienten, där det används för att återställa komponenttillståndet. Under återgivning på klientsidan (CSR, InteractiveWebAssembly) exponeras data i webbläsaren och får inte innehålla känslig, privat information. Under interaktiv återgivning på serversidan (interaktiv SSR, InteractiveServer), säkerställer ASP.NET Core Data Protection att data överförs på ett säkert sätt. Återgivningsläget InteractiveAuto kombinerar WebAssembly och serverinteraktivitet, så det är viktigt att beakta dataexponeringen för webbläsaren, som i fallet med CSR.
Om du vill bevara förrenderat tillstånd använder du [PersistentState] attributet för att bevara tillståndet i egenskaper. Egenskaper med det här attributet sparas automatiskt med hjälp av PersistentComponentState tjänsten under förinläsningen. Tillståndet hämtas när komponenten återges interaktivt eller om tjänsten instansieras.
Som standard serialiseras egenskaperna med serialiseraren System.Text.Json med standardinställningar och sparas i den förrenderade HTML-koden. Serialiseringen är inte trimmersäker och kräver att de typer som används bevaras. Mer information finns i Konfigurera Trimmer för ASP.NET Core Blazor.
Följande räknarkomponent bevarar räknartillståndet under förinläsningen och hämtar tillståndet för att initiera komponenten:
- Attributet [PersistentState]tillämpas på den nullbarainttypen (CurrentCount).
- Räknarens tillstånd tilldelas när nullär iOnInitializedoch återställs automatiskt när komponenten renderas interaktivt.
              PrerenderedCounter2.razor:
@page "/prerendered-counter-2"
@inject ILogger<PrerenderedCounter2> Logger
<PageTitle>Prerendered Counter 2</PageTitle>
<h1>Prerendered Counter 2</h1>
<p role="status">Current count: @CurrentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@code {
    [PersistentState]
    public int? CurrentCount { get; set; }
    protected override void OnInitialized()
    {
        if (CurrentCount is null)
        {
            CurrentCount = Random.Shared.Next(100);
            Logger.LogInformation("CurrentCount set to {Count}", CurrentCount);
        }
        else
        {
            Logger.LogInformation("CurrentCount restored to {Count}", CurrentCount);
        }
    }
    private void IncrementCount() => CurrentCount++;
}
När komponenten körs anges CurrentCount endast en gång under förberedande rendering. Värdet återställs när komponenten återställs. Följande är exempelutdata.
Anmärkning
Om appen använder interaktiv routning och sidan nås via en intern förbättrad navigering sker inte prerendering. Därför måste du utföra en fullständig sidåterläsning för komponenten för att se följande utdata. Mer information finns i avsnittet Interaktiv routning och prerendering .
info: BlazorSample.Components.Pages.PrerenderedCounter2[0]
CurrentCount set to 96
info: BlazorSample.Components.Pages.PrerenderedCounter2[0]
CurrentCount restored to 96
I följande exempel serialiserar tillståndet för flera komponenter av samma typ:
- Egenskaper som kommenterats med [PersistentState]attributet serialiseras under prerendering.
- 
              Direktivattributet@keyanvänds för att säkerställa att tillståndet är korrekt associerat med komponentinstansen.
- Egenskapen Elementinitieras iOnInitializedlivscykelmetoden för att undvika null-referensfel, på samma sätt som nullreferenser undviks för frågeparametrar och formulärdata.
              PersistentChild.razor:
<div>
    <p>Current count: @Element.CurrentCount</p>
    <button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
</div>
@code {
    [PersistentState]
    public State Element { get; set; }
    protected override void OnInitialized()
    {
        Element ??= new State();
    }
    private void IncrementCount()
    {
        Element.CurrentCount++;
    }
    private class State
    {
        public int CurrentCount { get; set; }
    }
}
              Parent.razor:
@page "/parent"
@foreach (var element in elements)
{
    <PersistentChild @key="element.Name" />
}
Serialisera tillstånd för tjänster
I följande exempel serialiseras tillståndet för en beroendeinjektionstjänst:
- Egenskaper som kommenteras med [PersistentState]attributet serialiseras under prerendering och deserialiseras när appen blir interaktiv.
- Tilläggsmetoden RegisterPersistentService används för att registrera tjänsten för beständighet. Återgivningsläget krävs eftersom återgivningsläget inte kan härledas från tjänsttypen. Använd något av följande värden: - 
              RenderMode.Server: Tjänsten är tillgänglig för återgivningsläget för interaktiv server.
- 
              RenderMode.Webassembly: Tjänsten är tillgänglig för interaktivt WebAssembly-återgivningsläge.
- 
              RenderMode.InteractiveAuto: Tjänsten är tillgänglig för både återgivningslägena interaktiv server och interaktiv webassembly om en komponent återges i något av dessa lägen.
 
- 
              
- Tjänsten löses under initieringen av ett interaktivt återgivningsläge och egenskaperna som kommenteras med [PersistentState]attributet deserialiseras.
Anmärkning
Endast bevarande av avgränsade tjänster stöds.
Serialiserade egenskaper identifieras från den faktiska tjänstinstansen:
- Med den här metoden kan du markera en abstraktion som en beständig tjänst.
- Gör att faktiska implementeringar kan vara interna eller olika typer.
- Stöder delad kod i olika sammansättningar.
- Resulterar i att varje instans visar samma egenskaper.
Följande räknartjänst, CounterTracker, markerar den aktuella antalsegenskapen CurrentCount med attributet [PersistentState]. Egenskapen serialiseras under prerendering och deserialiseras när appen blir interaktiv oavsett var tjänsten matas in.
              CounterTracker.cs:
public class CounterTracker
{
    [PersistentState]
    public int CurrentCount { get; set; }
    public void IncrementCount()
    {
        CurrentCount++;
    }
}
I Program-filen registrerar du den avgränsade tjänsten och registrerar tjänsten för persistens med RegisterPersistentService. I följande exempel CounterTracker är tjänsten tillgänglig för både interaktiva server- och interaktiva WebAssembly-återgivningslägen om en komponent renderas i något av dessa lägen eftersom den är registrerad med RenderMode.InteractiveAuto.
              Program Om filen inte redan använder Microsoft.AspNetCore.Components.Web namnområdet lägger du till följande using -instruktion överst i filen:
using Microsoft.AspNetCore.Components.Web;
Där tjänster är registrerade i Program filen:
builder.Services.AddScoped<CounterTracker>();
builder.Services.AddRazorComponents()
    .RegisterPersistentService<CounterTracker>(RenderMode.InteractiveAuto);
              CounterTracker Mata in tjänsten i en komponent och använd den för att öka en räknare. I demonstrationssyfte i följande exempel anges värdet för tjänstens CurrentCount egenskap endast till 10 under förinläsning.
              Pages/Counter.razor:
@page "/counter"
@inject CounterTracker CounterTracker
<PageTitle>Counter</PageTitle>
<h1>Counter</h1>
<p>Rendering: @RendererInfo.Name</p>
<p role="status">Current count: @CounterTracker.CurrentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@code {
    protected override void OnInitialized()
    {
        if (!RendererInfo.IsInteractive)
        {
            CounterTracker.CurrentCount = 10;
        }
    }
    private void IncrementCount()
    {
        CounterTracker.IncrementCount();
    }
}
Om du vill använda föregående komponent för att demonstrera beständigt antal 10 i CounterTracker.CurrentCountgår du till komponenten och uppdaterar webbläsaren, vilket utlöser prerendering. När prerendering inträffar, ser du kort "RendererInfo.Name" indikera "Static" innan den slutliga återgivningen visar "Server". Räknaren börjar vid 10.
              PersistentComponentState Använd tjänsten direkt i stället för den deklarativa modellen
Som ett alternativ till att använda den deklarativa modellen för att bevara tillståndet med [PersistentState] attributet kan du använda PersistentComponentState tjänsten direkt, vilket ger större flexibilitet för komplexa scenarier för tillståndsbeständighet. Anropa PersistentComponentState.RegisterOnPersisting för att registrera ett återanrop för att bevara komponenttillståndet under förinläsningen. Tillståndet hämtas när komponenten återges interaktivt. Gör anropet i slutet av initieringskoden för att undvika ett potentiellt låsningstillstånd under appavstängningen.
Följande exempel på räknarkomponent bevarar räknartillståndet under förbearbetning och återhämtar tillståndet för att initiera komponenten.
              PrerenderedCounter3.razor:
@page "/prerendered-counter-3"
@implements IDisposable
@inject ILogger<PrerenderedCounter3> Logger
@inject PersistentComponentState ApplicationState
<PageTitle>Prerendered Counter 3</PageTitle>
<h1>Prerendered Counter 3</h1>
<p role="status">Current count: @currentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@code {
    private int currentCount;
    private PersistingComponentStateSubscription persistingSubscription;
    protected override void OnInitialized()
    {
        if (!ApplicationState.TryTakeFromJson<int>(
            nameof(currentCount), out var restoredCount))
        {
            currentCount = Random.Shared.Next(100);
            Logger.LogInformation("currentCount set to {Count}", currentCount);
        }
        else
        {
            currentCount = restoredCount!;
            Logger.LogInformation("currentCount restored to {Count}", currentCount);
        }
        // Call at the end to avoid a potential race condition at app shutdown
        persistingSubscription = ApplicationState.RegisterOnPersisting(PersistCount);
    }
    private Task PersistCount()
    {
        ApplicationState.PersistAsJson(nameof(currentCount), currentCount);
        return Task.CompletedTask;
    }
    private void IncrementCount() => currentCount++;
    void IDisposable.Dispose() => persistingSubscription.Dispose();
}
När komponenten körs anges currentCount endast en gång under förberedande rendering. Värdet återställs när komponenten återställs. Följande är exempelutdata.
Anmärkning
Om appen använder interaktiv routning och sidan nås via en intern förbättrad navigering sker inte prerendering. Därför måste du utföra en fullständig sidåterläsning för komponenten för att se följande utdata. Mer information finns i avsnittet Interaktiv routning och prerendering .
info: BlazorSample.Components.Pages.PrerenderedCounter3[0]
currentCount set to 96
info: BlazorSample.Components.Pages.PrerenderedCounter3[0]
currentCount restored to 96
Om du vill bevara förinstallerat tillstånd bestämmer du vilket tillstånd som ska sparas med hjälp av PersistentComponentState-tjänsten. PersistentComponentState.RegisterOnPersisting registrerar ett återanrop för att bevara komponenttillståndet under förinläsningen. Tillståndet hämtas när komponenten återges interaktivt. Gör anropet i slutet av initieringskoden för att undvika ett potentiellt låsningstillstånd under appavstängningen.
Följande exempel på räknarkomponent bevarar räknartillståndet under förbearbetning och återhämtar tillståndet för att initiera komponenten.
              PrerenderedCounter2.razor:
@page "/prerendered-counter-2"
@implements IDisposable
@inject ILogger<PrerenderedCounter2> Logger
@inject PersistentComponentState ApplicationState
<PageTitle>Prerendered Counter 2</PageTitle>
<h1>Prerendered Counter 2</h1>
<p role="status">Current count: @currentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@code {
    private int currentCount;
    private PersistingComponentStateSubscription persistingSubscription;
    protected override void OnInitialized()
    {
        if (!ApplicationState.TryTakeFromJson<int>(
            nameof(currentCount), out var restoredCount))
        {
            currentCount = Random.Shared.Next(100);
            Logger.LogInformation("currentCount set to {Count}", currentCount);
        }
        else
        {
            currentCount = restoredCount!;
            Logger.LogInformation("currentCount restored to {Count}", currentCount);
        }
        // Call at the end to avoid a potential race condition at app shutdown
        persistingSubscription = ApplicationState.RegisterOnPersisting(PersistCount);
    }
    private Task PersistCount()
    {
        ApplicationState.PersistAsJson(nameof(currentCount), currentCount);
        return Task.CompletedTask;
    }
    void IDisposable.Dispose() => persistingSubscription.Dispose();
    private void IncrementCount() => currentCount++;
}
När komponenten körs anges currentCount endast en gång under förberedande rendering. Värdet återställs när komponenten återställs. Följande är exempelutdata.
Anmärkning
Om appen använder interaktiv routning och sidan nås via en intern förbättrad navigering sker inte prerendering. Därför måste du utföra en fullständig sidåterläsning för komponenten för att se följande utdata. Mer information finns i avsnittet Interaktiv routning och prerendering .
info: BlazorSample.Components.Pages.PrerenderedCounter2[0]
currentCount set to 96
info: BlazorSample.Components.Pages.PrerenderedCounter2[0]
currentCount restored to 96
Utökningsbarhet för serialisering för beständiga komponenttillstånd
Implementera en anpassad serialiserare med IPersistentComponentStateSerializer gränssnittet. Utan en registrerad anpassad serialiserare återgår serialiseringen till den befintliga JSON-serialiseringen.
Den anpassade serialiseraren är registrerad i appens Program fil. I följande exempel CustomUserSerializer är registrerad för User typen:
builder.Services.AddSingleton<IPersistentComponentStateSerializer<User>, 
    CustomUserSerializer>();
Typen sparas och återställs automatiskt med den anpassade serialiseraren:
[PersistentState] 
public User? CurrentUser { get; set; } = new();
Komponenter inbäddade i sidor och vyer (Razor Pages/MVC)
För komponenter som bäddas in i en sida eller vy av en Razor Pages- eller MVC-app måste du lägga till hjälpverktyget För att bevara komponenttillstånd med <persist-component-state /> HTML-taggen i den avslutande </body> taggen i appens layout. Detta krävs endast för Razor Pages- och MVC-appar. Mer information finns i Persist Component State Tag Helper in ASP.NET Core.
              Pages/Shared/_Layout.cshtml:
<body>
    ...
    <persist-component-state />
</body>
Interaktiv routning och prerendering
När den Routes komponenten inte definierar ett återgivningsläge använder appen interaktivitet och navigering per sida/komponent. Med hjälp av navigering per sida/komponent hanteras intern navigering genom förbättrad routning när appen blir interaktiv. "Intern navigering" i den här kontexten innebär att URL-målet för navigeringshändelsen är en Blazor slutpunkt i appen.
Blazor stöder hantering av beständiga komponenttillstånd under förbättrad navigering. Tillstånd som bevaras under utökad navigering kan läsas av interaktiva komponenter på sidan.
Som standard läses beständiga komponenttillstånd endast in av interaktiva komponenter när de först läses in på sidan. Detta förhindrar att viktiga tillstånd, till exempel data i en redigerad webbformulär, skrivs över om ytterligare förbättrade navigeringshändelser till samma sida inträffar när komponenten har lästs in.
Om data är skrivskyddade och inte ändras ofta kan du välja att tillåta uppdateringar under förbättrad navigering genom att ange AllowUpdates = true[PersistentState] attributet. Detta är användbart för scenarier som att visa cachelagrade data som är dyra att hämta men som inte ändras ofta. I följande exempel visas hur väderprognosdata används AllowUpdates :
[PersistentState(AllowUpdates = true)]
public WeatherForecast[]? Forecasts { get; set; }
protected override async Task OnInitializedAsync()
{
    Forecasts ??= await ForecastService.GetForecastAsync();
}
Om du vill hoppa över återställningstillståndet under prerendering anger du RestoreBehavior till SkipInitialValue:
[PersistentState(RestoreBehavior = RestoreBehavior.SkipInitialValue)]
public string NoPrerenderedData { get; set; }
Om du vill hoppa över återställningstillståndet under återanslutningen anger du RestoreBehavior till SkipLastSnapshot. Detta kan vara användbart för att säkerställa nya data efter återanslutning:
[PersistentState(RestoreBehavior = RestoreBehavior.SkipLastSnapshot)]
public int CounterNotRestoredOnReconnect { get; set; }
Anropa PersistentComponentState.RegisterOnRestoring för att registrera ett återanrop för att imperativt kontrollera hur tillståndet återställs, ungefär som hur PersistentComponentState.RegisterOnPersisting ger fullständig kontroll över hur tillståndet bevaras.
Tjänsten PersistentComponentState fungerar bara vid den inledande sidinläsningen och inte vid förbättrade interna sidnavigeringshändelser.
Om appen utför en fullständig (icke-utökad) navigering till en sida med beständiga komponenttillstånd görs det beständiga tillståndet tillgängligt för appen att använda när den blir interaktiv.
Om en interaktiv krets redan har upprättats och en förbättrad navigering utförs på en sida med beständiga komponenttillstånd , görs inte tillståndet tillgängligt i den befintliga kretsen för komponenten som ska användas. Det finns ingen prerendering för den interna sidbegäran och PersistentComponentState-tjänsten är inte medveten om att en förbättrad navigering har inträffat. Det finns ingen mekanism för att leverera tillståndsuppdateringar till komponenter som redan körs på en befintlig krets. Anledningen till detta är att Blazor endast stöder överföring av tillstånd från servern till klienten när körtiden initieras, inte efter att körtiden har startat.
Om du avaktiverar förbättrad navigering, vilket minskar prestandan men också undviker problemet med inläsningstillstånd med PersistentComponentState för interna sidbegäranden, täcks detta i ASP.NET Core Blazor-routning och navigering. Alternativt kan du uppdatera appen till .NET 10 eller senare, där Blazor stöder hantering av beständiga komponenttillstånd när du använder utökad navigering.
ASP.NET Core