Nota
L'accesso a questa pagina richiede l'autorizzazione. Puoi provare ad accedere o a cambiare directory.
L'accesso a questa pagina richiede l'autorizzazione. Puoi provare a cambiare directory.
Senza rendere persistente lo stato del componente, lo stato usato durante il prerendering viene perso e deve essere ricreato quando l'app viene completamente caricata. Se uno stato viene creato in modo asincrono, l'interfaccia utente può sfarfallare perché l'interfaccia utente prerenderizzata viene sostituita quando il componente viene rendirizzato nuovamente.
Si consideri il componente contatore seguente PrerenderedCounter1 . Il componente imposta un valore iniziale casuale del contatore durante il prerendering nel OnInitialized metodo del ciclo di vita. Quando il componente esegue il rendering in modo interattivo, il valore del conteggio iniziale viene sostituito quando OnInitialized viene eseguito una seconda volta.
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++;
}
Annotazioni
Se l'app adotta il routing interattivo e la pagina viene raggiunta tramite una navigazione avanzata interna , il prerendering non si verifica. Pertanto, è necessario eseguire un ricaricamento di pagina completo per il PrerenderedCounter1 componente per visualizzare l'output seguente. Per ulteriori informazioni, consultare la sezione Routing interattivo e prerendering.
Eseguire l'app ed esaminare i log dal componente. Di seguito è riportato un output di esempio.
info: BlazorSample.Components.Pages.PrerenderedCounter1[0]
currentCount set to 41
info: BlazorSample.Components.Pages.PrerenderedCounter1[0]
currentCount set to 92
Il primo conteggio registrato si verifica durante il prerendering. Il conteggio viene nuovamente impostato dopo il prerendering quando il componente viene nuovamente renderizzato. C'è anche uno sfarfallio nell'interfaccia utente quando il conteggio viene aggiornato da 41 a 92.
Per mantenere il valore iniziale del contatore durante il prerendering, Blazor consente la persistenza dello stato in una pagina prerenderata usando il servizio PersistentComponentState (e per i componenti incorporati nelle pagine o nelle visualizzazioni di pagine Razor o app MVC, l'Helper Tag Persistenza Stato del Componente).
Inizializzando i componenti con lo stesso stato usato durante la pre-esecuzione, tutti i passaggi di inizializzazione costosi vengono eseguiti una sola volta. L'interfaccia utente renderizzata corrisponde anche all'interfaccia utente prerenderizzata, quindi non si verifica alcun sfarfallio nel browser.
Lo stato prerenderato persistente viene trasferito al client, in cui viene usato per ripristinare lo stato del componente. Durante il rendering lato client (CSR, InteractiveWebAssembly), i dati vengono esposti al browser e non devono contenere informazioni riservate e private. Durante il rendering lato server interattivo (SSR interattivo, InteractiveServer), la protezione dei dati ASP.NET Core garantisce che i dati vengano trasferiti in modo sicuro. La InteractiveAuto modalità di rendering combina l'interattività di WebAssembly e del server, quindi è necessario considerare l'esposizione dei dati al browser, come nel caso CSR.
Per mantenere lo stato prerenderato, usare l'attributo[PersistentState] per rendere persistente lo stato nelle proprietà. Le proprietà con questo attributo vengono memorizzate automaticamente usando il servizio PersistentComponentState durante il prerendering. Lo stato viene recuperato quando il componente esegue il rendering interattivo o viene creata un'istanza del servizio.
Per impostazione predefinita, le proprietà vengono serializzate usando il System.Text.Json serializzatore con le impostazioni predefinite e mantenute nel codice HTML pre-predefinito. La serializzazione non è sicura per i trimmer e richiede la conservazione dei tipi utilizzati. Per altre informazioni, vedere Configurare Trimmer per ASP.NET Core Blazor.
Il componente contatore seguente mantiene lo stato del contatore durante il prerendering e recupera lo stato per inizializzare il componente:
-
L'attributo
[PersistentState]viene applicato al tipo nullableint(CurrentCount). - Lo stato del contatore viene assegnato quando si trova il
nullall'interno delOnInitialized, e viene ripristinato automaticamente quando il componente viene renderizzato in modo interattivo.
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++;
}
Quando il componente viene eseguito, CurrentCount viene impostato una sola volta durante la pre-esecuzione. Il valore viene ripristinato quando il componente viene sottoposto a rerendering. Di seguito è riportato un output di esempio.
Annotazioni
Se l'app adotta il routing interattivo e la pagina viene raggiunta tramite una navigazione avanzata interna , il prerendering non si verifica. Pertanto, è necessario eseguire un ricaricamento di pagina completo per il componente per visualizzare l'output seguente. Per ulteriori informazioni, consultare la sezione Routing interattivo e prerendering.
info: BlazorSample.Components.Pages.PrerenderedCounter2[0]
CurrentCount set to 96
info: BlazorSample.Components.Pages.PrerenderedCounter2[0]
CurrentCount restored to 96
Nell'esempio seguente che serializza lo stato per più componenti dello stesso tipo:
- Le proprietà annotate con l'attributo
[PersistentState]vengono serializzate durante il prerendering. -
L'attributo
@keydi direttiva viene usato per assicurarsi che lo stato sia associato correttamente all'istanza del componente. - La
Elementproprietà viene inizializzata nelOnInitializedmetodo del ciclo di vita per evitare eccezioni di riferimento Null, in modo analogo al modo in cui i riferimenti Null vengono evitati per i parametri di query e i dati del modulo.
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" />
}
Serializzare lo stato per i servizi
Nell'esempio seguente che serializza dello stato per un servizio di iniezione delle dipendenze:
- Le proprietà annotate con l'attributo
[PersistentState]vengono serializzate durante il prerendering e deserializzate quando l'app diventa interattiva. - Il RegisterPersistentService metodo di estensione viene utilizzato per registrare il servizio a fini di persistenza. La modalità di rendering è necessaria perché la modalità di rendering non può essere dedotta dal tipo di servizio. Usare uno dei valori seguenti:
-
RenderMode.Server: il servizio è disponibile per la modalità di rendering di Interactive Server. -
RenderMode.Webassembly: il servizio è disponibile per la modalità di rendering Interactive Webassembly. -
RenderMode.InteractiveAuto: il servizio è disponibile per le modalità di rendering Interactive Server e Interactive Webassembly se un componente esegue il rendering in una di queste modalità.
-
- Il servizio viene risolto durante l'inizializzazione di una modalità di rendering interattiva e le proprietà annotate con l'attributo
[PersistentState]vengono deserializzate.
Annotazioni
È supportata solo la persistenza dei servizi con ambito.
Le proprietà serializzate vengono identificate dall'istanza del servizio effettiva:
- Questo approccio consente di contrassegnare un'astrazione come servizio permanente.
- Consente alle implementazioni effettive di essere tipi interni o diversi.
- Supporta il codice condiviso in assembly diversi.
- Ogni istanza risulta nel mostrare le stesse proprietà.
Il seguente servizio contatore, CounterTracker, contrassegna la proprietà della conteggio corrente, CurrentCount, con l'attributo [PersistentState]. La proprietà viene serializzata durante il prerendering e deserializzata non appena l'app diventa interattiva, in cui viene inserito il servizio.
CounterTracker.cs:
public class CounterTracker
{
[PersistentState]
public int CurrentCount { get; set; }
public void IncrementCount()
{
CurrentCount++;
}
}
Nel file Program, registrare il servizio con ambito specificato e registrare il servizio per la persistenza con RegisterPersistentService. Nell'esempio seguente il CounterTracker servizio è disponibile per le modalità di rendering Interactive Server e Interactive WebAssembly se un componente esegue il rendering in una di queste modalità perché è registrato con RenderMode.InteractiveAuto.
Se il Program file non usa già lo Microsoft.AspNetCore.Components.Web spazio dei nomi, aggiungere l'istruzione seguente using all'inizio del file.
using Microsoft.AspNetCore.Components.Web;
Posizione in cui i servizi vengono registrati nel Program file:
builder.Services.AddScoped<CounterTracker>();
builder.Services.AddRazorComponents()
.RegisterPersistentService<CounterTracker>(RenderMode.InteractiveAuto);
Inserire il CounterTracker servizio in un componente e usarlo per incrementare un contatore. A scopo dimostrativo, nel seguente esempio, il valore della proprietà del servizio CurrentCount è impostato su 10 solo durante la pre-renderizzazione.
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();
}
}
Per usare il componente precedente per dimostrare come mantenere il conteggio di 10 in CounterTracker.CurrentCount, accedere al componente e aggiornare il browser, il che attiva il prerendering. Quando si verifica la pre-esecuzione, RendererInfo.Name indica brevemente "Static" prima di visualizzare "Server" dopo il rendering finale. Il contatore inizia a 10.
Usare direttamente il PersistentComponentState servizio anziché il modello dichiarativo
In alternativa all'uso del modello dichiarativo per rendere persistente lo stato con l'attributo[PersistentState] , è possibile usare direttamente il PersistentComponentState servizio, che offre maggiore flessibilità per scenari di persistenza dello stato complesso. Chiamare PersistentComponentState.RegisterOnPersisting per registrare un callback per mantenere lo stato del componente durante la pre-renderizzazione. Lo stato viene recuperato quando il componente esegue il rendering interattivo. Effettuare la chiamata alla fine del codice di inizializzazione per evitare una potenziale race condition durante l'arresto dell'app.
Nell'esempio seguente del componente contatore, lo stato del contatore viene mantenuto durante la pre-renderizzazione e recuperato per inizializzare il componente.
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();
}
Quando il componente viene eseguito, currentCount viene impostato una sola volta durante la pre-esecuzione. Il valore viene ripristinato quando il componente viene sottoposto a rerendering. Di seguito è riportato un output di esempio.
Annotazioni
Se l'app adotta il routing interattivo e la pagina viene raggiunta tramite una navigazione avanzata interna , il prerendering non si verifica. Pertanto, è necessario eseguire un ricaricamento di pagina completo per il componente per visualizzare l'output seguente. Per ulteriori informazioni, consultare la sezione Routing interattivo e prerendering.
info: BlazorSample.Components.Pages.PrerenderedCounter3[0]
currentCount set to 96
info: BlazorSample.Components.Pages.PrerenderedCounter3[0]
currentCount restored to 96
Per mantenere lo stato prerenderato, decidere quale stato rendere persistente usando il PersistentComponentState servizio. PersistentComponentState.RegisterOnPersisting registra un callback per rendere persistente lo stato del componente durante il pre-riavvio. Lo stato viene recuperato quando il componente esegue il rendering interattivo. Effettuare la chiamata alla fine del codice di inizializzazione per evitare una potenziale race condition durante l'arresto dell'app.
Nell'esempio seguente del componente contatore, lo stato del contatore viene mantenuto durante la pre-renderizzazione e recuperato per inizializzare il componente.
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++;
}
Quando il componente viene eseguito, currentCount viene impostato una sola volta durante la pre-esecuzione. Il valore viene ripristinato quando il componente viene sottoposto a rerendering. Di seguito è riportato un output di esempio.
Annotazioni
Se l'app adotta il routing interattivo e la pagina viene raggiunta tramite una navigazione avanzata interna , il prerendering non si verifica. Pertanto, è necessario eseguire un ricaricamento di pagina completo per il componente per visualizzare l'output seguente. Per ulteriori informazioni, consultare la sezione Routing interattivo e prerendering.
info: BlazorSample.Components.Pages.PrerenderedCounter2[0]
currentCount set to 96
info: BlazorSample.Components.Pages.PrerenderedCounter2[0]
currentCount restored to 96
Estendibilità della serializzazione per lo stato del componente persistente
Implementare un serializzatore personalizzato con PersistentComponentStateSerializer<T>. Senza un serializzatore personalizzato registrato, la serializzazione esegue il fallback alla serializzazione JSON esistente.
Il serializzatore personalizzato viene registrato nel file dell'app Program . Nell'esempio seguente l'oggetto CustomUserSerializer viene registrato per il TUser tipo :
builder.Services.AddSingleton<PersistentComponentStateSerializer<TUser>,
CustomUserSerializer>();
Il tipo viene salvato in modo permanente e ripristinato automaticamente con il serializzatore personalizzato:
[PersistentState]
public User? CurrentUser { get; set; } = new();
Componenti incorporati in pagine e visualizzazioni (Razor Pages/MVC)
Per i componenti incorporati in una pagina o in una visualizzazione di un'app Razor Pages o MVC, devi aggiungere il Tag Helper "Persist Component State" con il tag HTML all'interno del tag di chiusura <persist-component-state /> del layout dell'app. Questa operazione è necessaria solo per Razor le app Pages e MVC. Per altre informazioni, vedere Persist Component State Tag Helper in ASP.NET Core.For more information, see Persist Component State Tag Helper in ASP.NET Core.
Pages/Shared/_Layout.cshtml:
<body>
...
<persist-component-state />
</body>
Instradamento interattivo e prerendering
Quando il componente Routes non definisce una modalità di rendering, l'app usa interattività e navigazione per pagina/componente. Usando lo spostamento per pagina/componente, lo spostamento interno viene gestito dal routing avanzato dopo che l'app diventa interattiva. "Spostamento interno" in questo contesto significa che la destinazione URL dell'evento di spostamento è un Blazor endpoint all'interno dell'app.
Blazor supporta la gestione dello stato del componente persistente durante la navigazione avanzata. Lo stato persistente durante la navigazione avanzata può essere letto da componenti interattivi nella pagina.
Per impostazione predefinita, lo stato del componente persistente viene caricato solo dai componenti interattivi quando vengono inizialmente caricati nella pagina. Ciò impedisce che lo stato importante, ad esempio i dati in una webform modificata, venga sovrascritto se si verificano eventi di spostamento avanzati aggiuntivi nella stessa pagina dopo il caricamento del componente.
Se i dati sono di sola lettura e non cambiano di frequente, acconsentire esplicitamente per consentire gli aggiornamenti durante la navigazione avanzata impostando AllowUpdates = truesull'attributo[PersistentState] . Ciò è utile per scenari come la visualizzazione di dati memorizzati nella cache costosi da recuperare, ma non cambia spesso. L'esempio seguente illustra l'uso di per i dati delle AllowUpdates previsioni meteo:
[PersistentState(AllowUpdates = true)]
public WeatherForecast[]? Forecasts { get; set; }
protected override async Task OnInitializedAsync()
{
Forecasts ??= await ForecastService.GetForecastAsync();
}
Per ignorare lo stato di ripristino durante la prerendering, impostare su RestoreBehaviorSkipInitialValue:
[PersistentState(RestoreBehavior = RestoreBehavior.SkipInitialValue)]
public string NoPrerenderedData { get; set; }
Per ignorare lo stato di ripristino durante la riconnessione, impostare su RestoreBehaviorSkipLastSnapshot. Ciò può essere utile per garantire i dati aggiornati dopo la riconnessione:
[PersistentState(RestoreBehavior = RestoreBehavior.SkipLastSnapshot)]
public int CounterNotRestoredOnReconnect { get; set; }
Chiamare PersistentComponentState.RegisterOnRestoring per registrare un callback per controllare in modo imperativo il modo in cui viene ripristinato lo stato, in modo analogo a come PersistentComponentState.RegisterOnPersisting fornisce il controllo completo della modalità di persistenza dello stato.
Il servizio PersistentComponentState funziona solo sul caricamento della pagina iniziale e non sugli eventi di spostamento di pagina avanzati interni.
Se l'app esegue uno spostamento completo (non avanzato) a una pagina che usa lo stato del componente persistente, lo stato persistente viene reso disponibile per l'uso dell'app quando diventa interattivo.
Se è già stato stabilito un circuito interattivo e viene eseguita una navigazione avanzata in una pagina che utilizza lo stato del componente persistente, lo stato non viene reso disponibile nel circuito esistente per il componente da usare. Non c'è pre-rendering per la richiesta di pagina interna e il servizio PersistentComponentState non è a conoscenza del fatto che si è verificata una navigazione migliorata. Non esiste alcun meccanismo per distribuire gli aggiornamenti dello stato ai componenti già in esecuzione in un circuito esistente. Il motivo è che Blazor supporta solo il passaggio dello stato dal server al client al momento dell'inizializzazione del runtime, non dopo l'avvio del runtime.
La disabilitazione della navigazione avanzata, che riduce le prestazioni, ma evita anche il problema di caricamento dello stato con PersistentComponentState per le richieste di pagina interne, è descritta in ASP.NET navigazione CoreBlazor. In alternativa, aggiornare l'app a .NET 10 o versione successiva, in cui Blazor supporta la gestione dello stato del componente persistente durante la navigazione avanzata.