Nuta
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować się zalogować lub zmienić katalog.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Bez utrwalania stanu składnika stan używany podczas prerenderingu zostanie utracony i musi zostać utworzony ponownie, gdy aplikacja zostanie w pełni załadowana. Jeśli jakikolwiek stan jest tworzony asynchronicznie, interfejs użytkownika może migać, ponieważ wcześniej wyrenderowany interfejs użytkownika jest zastępowany, gdy składnik jest ponownie renderowany.
Rozważ następujący PrerenderedCounter1 składnik licznika. Komponent ustawia początkową losową wartość licznika podczas przedrenderowania w OnInitialized metodzie cyklu życia. Gdy składnik następnie renderuje interakcyjnie, początkowa wartość licznika jest zastępowana podczas OnInitialized wykonywania po raz drugi.
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++;
}
Uwaga / Notatka
Jeśli aplikacja korzysta z routingu interakcyjnego, a strona jest osiągana za pośrednictwem wewnętrznej rozszerzonej nawigacji, prerenderowanie nie występuje. W związku z tym należy wykonać ponowne ładowanie pełnej strony dla PrerenderedCounter1 składnika, aby wyświetlić następujące dane wyjściowe. Aby uzyskać dodatkowe informacje, przejdź do sekcji Interaktywny routing i przetwarzanie wstępne.
Uruchom aplikację i przeanalizuj logi ze składnika. Poniżej przedstawiono przykładowe dane wyjściowe.
info: BlazorSample.Components.Pages.PrerenderedCounter1[0]
currentCount set to 41
info: BlazorSample.Components.Pages.PrerenderedCounter1[0]
currentCount set to 92
Pierwsze zarejestrowane zliczenie występuje podczas prerenderowania. Liczba jest ponownie ustawiana po wstępnym renderowaniu, gdy składnik jest ponownie renderowany. W interfejsie użytkownika występuje również migotanie, gdy wartość licznika zmienia się z 41 na 92.
Aby zachować początkową wartość licznika podczas prerenderingu, Blazor obsługuje utrwalanie stanu na prerenderowanej stronie przy użyciu usługi PersistentComponentState (oraz dla składników osadzonych na stronach lub w widokach stron Razor lub aplikacji MVC, Pomocnik tagu utrwalania stanu składnika).
Inicjując składniki o tym samym stanie używanym podczas prerenderingu, wszystkie kosztowne kroki inicjowania są wykonywane tylko raz. Renderowany interfejs użytkownika jest również zgodny ze wstępnie zdefiniowanym interfejsem użytkownika, więc w przeglądarce nie występuje migotanie.
Stan zapisany po wstępnym renderowaniu jest przenoszony na stronę klienta, gdzie jest używany do przywrócenia stanu komponentu. Podczas renderowania po stronie klienta (CSR, InteractiveWebAssembly) dane są udostępniane w przeglądarce i nie mogą zawierać poufnych, prywatnych informacji. Podczas interaktywnego renderowania po stronie serwera (interakcyjne usługi SSR, InteractiveServer) ASP.NET Core Data Protection zapewnia bezpieczny transfer danych. Tryb renderowania InteractiveAuto łączy WebAssembly i interaktywność serwera, dlatego konieczne jest rozważenie ujawnienia danych w przeglądarce, tak jak w przypadku CSR.
Aby zachować stan wstępnego renderowania, użyj atrybutu[PersistentState], aby utrwalić stan we właściwościach. Właściwości z tym atrybutem są automatycznie utrwalane przy użyciu PersistentComponentState usługi podczas prerenderingu. Stan jest pobierany, gdy składnik jest renderowany interaktywnie lub usługa jest tworzona.
Domyślnie właściwości są serializowane przy użyciu serializatora System.Text.Json z ustawieniami domyślnymi i utrwalane w prerendered HTML. Serializacja nie jest bezpieczna i wymaga zachowania używanych typów. Aby uzyskać więcej informacji, zobacz Configure the Trimmer for ASP.NET Core (Konfigurowanie programu Trimmer dla platformy ASP.NET Core Blazor).
Następujący komponent licznika zachowuje stan licznika podczas prerenderingu i pobiera ten stan, aby zainicjować komponent:
- Atrybut
[PersistentState]jest stosowany do typu nullableint(CurrentCount). - Stan licznika jest przypisywany w momencie
nullOnInitialized, a następnie automatycznie przywracany, gdy składnik jest renderowany interaktywnie.
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++;
}
Gdy składnik jest wykonywany, CurrentCount jest ustawiany tylko raz podczas prerenderingu. Wartość jest przywracana, gdy składnik jest ponownie renderowany. Poniżej przedstawiono przykładowe dane wyjściowe.
Uwaga / Notatka
Jeśli aplikacja korzysta z routingu interakcyjnego, a strona jest osiągana za pośrednictwem wewnętrznej rozszerzonej nawigacji, prerenderowanie nie występuje. W związku z tym należy wykonać ponowne ładowanie pełnej strony dla składnika, aby wyświetlić następujące dane wyjściowe. Aby uzyskać dodatkowe informacje, przejdź do sekcji Interaktywny routing i przetwarzanie wstępne.
info: BlazorSample.Components.Pages.PrerenderedCounter2[0]
CurrentCount set to 96
info: BlazorSample.Components.Pages.PrerenderedCounter2[0]
CurrentCount restored to 96
W poniższym przykładzie serializuje stan wielu składników tego samego typu:
- Właściwości oznaczone atrybutem
[PersistentState]są serializowane podczas prerenderingu. - Atrybut
@keydyrektywy służy do upewnienia się, że stan jest prawidłowo powiązany z instancją składnika. - Właściwość
Elementjest inicjowana w metodzie cyklu życiaOnInitialized, aby uniknąć wyjątków powodowanych odwołaniami do wartości null, podobnie jak w przypadku uniknięcia takich odwołań w parametrach zapytania i danych formularza.
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" />
}
Serializacja stanu dla usług
W poniższym przykładzie dotyczącym serializacji stanu dla usługi korzystającej z wstrzykiwania zależności:
- Właściwości oznaczone atrybutem
[PersistentState]są serializowane podczas prerenderingu i deserializowane, gdy aplikacja staje się interaktywna. - Metoda RegisterPersistentService rozszerzenia służy do rejestrowania usługi pod kątem trwałości. Tryb renderowania jest wymagany, ponieważ nie można wywnioskować trybu renderowania z typu usługi. Użyj dowolnej z następujących wartości:
-
RenderMode.Server: Usługa jest dostępna dla trybu renderowania serwera interaktywnego. -
RenderMode.Webassembly: Usługa jest dostępna dla trybu renderowania Interactive Webassembly. -
RenderMode.InteractiveAuto: Usługa jest dostępna zarówno dla trybów renderowania Interactive Server, jak i Interactive Webassembly, jeśli składnik jest renderowany w jednym z tych trybów.
-
- Usługa jest rozwiązywana podczas inicjowania interaktywnego trybu renderowania, a właściwości oznaczone z atrybutem
[PersistentState]są deserializowane.
Uwaga / Notatka
Obsługiwane jest tylko utrzymywanie usług o określonym zakresie.
Właściwości serializowane są identyfikowane na podstawie rzeczywistego wystąpienia usługi.
- Takie podejście umożliwia oznaczenie abstrakcji jako usługi trwałej.
- Umożliwia realizację wewnętrznych implementacji lub implementacji różnych typów.
- Obsługuje kod udostępniony w różnych zestawach.
- Wyniki w każdym wystąpieniu ujawniają te same właściwości.
Następująca usługa licznikowa, CounterTracker, oznacza swoją bieżącą właściwość 'count', CurrentCount, używając atrybutu[PersistentState]. Właściwość jest serializowana podczas prerenderingu i deserializowana, gdy aplikacja staje się interaktywna w każdym miejscu, gdzie usługa jest wstrzykiwana.
CounterTracker.cs:
public class CounterTracker
{
[PersistentState]
public int CurrentCount { get; set; }
public void IncrementCount()
{
CurrentCount++;
}
}
Program W pliku zarejestruj usługę o określonym zakresie i zarejestruj usługę pod kątem trwałości za pomocą polecenia RegisterPersistentService. W poniższym przykładzie usługa CounterTracker dostępna jest zarówno w trybie renderowania Interaktywnego Serwera, jak i Interaktywnego WebAssembly, ponieważ składnik renderuje się w jednym z tych trybów, gdyż jest zarejestrowany dzięki RenderMode.InteractiveAuto.
Program Jeśli plik jeszcze nie używa przestrzeni nazw Microsoft.AspNetCore.Components.Web, dodaj następującą deklarację using na początku pliku:
using Microsoft.AspNetCore.Components.Web;
Gdzie usługi są zarejestrowane w Program pliku:
builder.Services.AddScoped<CounterTracker>();
builder.Services.AddRazorComponents()
.RegisterPersistentService<CounterTracker>(RenderMode.InteractiveAuto);
Wstrzyknij usługę CounterTracker do składnika i użyj jej do inkrementacji licznika. Dla celów demonstracyjnych w poniższym przykładzie wartość właściwości usługi CurrentCount jest ustawiona na 10 tylko podczas prerenderingu.
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();
}
}
Aby użyć wspomnianego składnika w celu zademonstrowania zachowania liczby 10 w CounterTracker.CurrentCount, przejdź do tego składnika i odśwież przeglądarkę, co wyzwala wyrenderowanie wstępne. W trakcie prerenderingu na krótko zobaczysz "RendererInfo.Name" wskazujące "Static", zanim po zakończeniu renderowania pojawi się "Server". Licznik zaczyna się od 10.
PersistentComponentState Używanie usługi bezpośrednio zamiast modelu deklaratywnego
Alternatywą dla używania modelu deklaratywnego do utrwalania stanu za pomocą atrybutu[PersistentState] jest bezpośrednie użycie PersistentComponentState usługi, co zapewnia większą elastyczność w przypadku złożonych scenariuszy trwałości stanu. Aby zarejestrować wywołanie zwrotne do utrwalenia stanu składnika podczas prerenderingu, użyj PersistentComponentState.RegisterOnPersisting. Stan jest pobierany, gdy składnik jest renderowany interaktywnie. Wykonaj wywołanie na końcu kodu inicjowania, aby uniknąć potencjalnego stanu wyścigu podczas zamykania aplikacji.
Poniższy przykład składnika licznika utrwala stan licznika podczas wstępnego renderowania i pobiera stan w celu inicjalizacji składnika.
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();
}
Gdy składnik jest wykonywany, currentCount jest ustawiany tylko raz podczas prerenderingu. Wartość jest przywracana, gdy składnik jest ponownie renderowany. Poniżej przedstawiono przykładowe dane wyjściowe.
Uwaga / Notatka
Jeśli aplikacja korzysta z routingu interakcyjnego, a strona jest osiągana za pośrednictwem wewnętrznej rozszerzonej nawigacji, prerenderowanie nie występuje. W związku z tym należy wykonać ponowne ładowanie pełnej strony dla składnika, aby wyświetlić następujące dane wyjściowe. Aby uzyskać dodatkowe informacje, przejdź do sekcji Interaktywny routing i przetwarzanie wstępne.
info: BlazorSample.Components.Pages.PrerenderedCounter3[0]
currentCount set to 96
info: BlazorSample.Components.Pages.PrerenderedCounter3[0]
currentCount restored to 96
Aby zachować stan wstępnego, zdecyduj, jaki stan ma być trwały przy użyciu PersistentComponentState usługi. PersistentComponentState.RegisterOnPersisting rejestruje wywołanie zwrotne w celu utrwalania stanu składnika podczas wstępnego renderowania. Stan jest pobierany, gdy składnik jest renderowany interaktywnie. Wykonaj wywołanie na końcu kodu inicjowania, aby uniknąć potencjalnego stanu wyścigu podczas zamykania aplikacji.
Poniższy przykład składnika licznika utrwala stan licznika podczas wstępnego renderowania i pobiera stan w celu inicjalizacji składnika.
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++;
}
Gdy składnik jest wykonywany, currentCount jest ustawiany tylko raz podczas prerenderingu. Wartość jest przywracana, gdy składnik jest ponownie renderowany. Poniżej przedstawiono przykładowe dane wyjściowe.
Uwaga / Notatka
Jeśli aplikacja korzysta z routingu interakcyjnego, a strona jest osiągana za pośrednictwem wewnętrznej rozszerzonej nawigacji, prerenderowanie nie występuje. W związku z tym należy wykonać ponowne ładowanie pełnej strony dla składnika, aby wyświetlić następujące dane wyjściowe. Aby uzyskać dodatkowe informacje, przejdź do sekcji Interaktywny routing i przetwarzanie wstępne.
info: BlazorSample.Components.Pages.PrerenderedCounter2[0]
currentCount set to 96
info: BlazorSample.Components.Pages.PrerenderedCounter2[0]
currentCount restored to 96
Rozszerzalność serializacji dla stanu trwałego składnika
Zaimplementuj niestandardowy serializator za pomocą polecenia PersistentComponentStateSerializer<T>. Bez zarejestrowanego serializatora niestandardowego serializacja wraca do istniejącej serializacji JSON.
Niestandardowy serializator jest zarejestrowany w pliku aplikacji Program . W poniższym przykładzie CustomUserSerializer parametr jest zarejestrowany dla TUser typu:
builder.Services.AddSingleton<PersistentComponentStateSerializer<TUser>,
CustomUserSerializer>();
Typ jest automatycznie utrwalany i przywracany za pomocą niestandardowego serializatora:
[PersistentState]
public User? CurrentUser { get; set; } = new();
Komponenty osadzone na stronach i widokach (Razor Pages/MVC)
W przypadku składników osadzonych na stronie lub widoku aplikacji Razor Pages lub MVC, należy dodać Pomocnika Zapisywania Stanu Składnika z tagiem wewnątrz zamykającego się tagu <persist-component-state /> układu aplikacji. Jest to wymagane tylko w przypadku Razor aplikacji Pages i MVC. Aby uzyskać więcej informacji, zobacz Pomocnik Tagu Utrwalania Stanu Składnika w ASP.NET Core.
Pages/Shared/_Layout.cshtml:
<body>
...
<persist-component-state />
</body>
Routing interakcyjny i prerenderowanie
Gdy składnik Routes nie definiuje trybu renderowania, aplikacja korzysta z interakcyjności poszczególnych stron/składników i nawigacji. Korzystając z nawigacji między stronami/składnikami, nawigacja wewnętrzna jest obsługiwana przez rozszerzony routing po tym, jak aplikacja stanie się interaktywna. "Nawigacja wewnętrzna" w tym kontekście oznacza, że miejsce docelowe adresu URL zdarzenia nawigacji jest Blazor punktem końcowym wewnątrz aplikacji.
Blazor obsługuje stan trwałego składnika podczas rozszerzonej nawigacji. Stan utrwalone podczas nawigacji rozszerzonej może być odczytywany przez interaktywne składniki na stronie.
Domyślnie stan składnika trwałego jest ładowany tylko przez składniki interakcyjne, gdy są one początkowo ładowane na stronie. Zapobiega to zastępowaniu ważnych stanów, takich jak dane w edytowanym formularzu internetowym, jeśli po załadowaniu składnika wystąpią dodatkowe rozszerzone zdarzenia nawigacji na tej samej stronie.
Jeśli dane są tylko do odczytu i nie zmieniają się często, należy wyrazić zgodę na zezwalanie na aktualizacje podczas rozszerzonej nawigacji przez ustawienie AllowUpdates = trueatrybutu[PersistentState]. Jest to przydatne w scenariuszach, takich jak wyświetlanie buforowanych danych, które są kosztowne do pobrania, ale nie zmienia się często. W poniższym przykładzie pokazano użycie danych AllowUpdates prognozy pogody:
[PersistentState(AllowUpdates = true)]
public WeatherForecast[]? Forecasts { get; set; }
protected override async Task OnInitializedAsync()
{
Forecasts ??= await ForecastService.GetForecastAsync();
}
Aby pominąć przywracanie stanu podczas prerenderingu, ustaw wartość RestoreBehaviorSkipInitialValue:
[PersistentState(RestoreBehavior = RestoreBehavior.SkipInitialValue)]
public string NoPrerenderedData { get; set; }
Aby pominąć przywracanie stanu podczas ponownego nawiązywania połączenia, ustaw wartość RestoreBehaviorSkipLastSnapshot. Może to być przydatne, aby zapewnić nowe dane po ponownym połączeniu:
[PersistentState(RestoreBehavior = RestoreBehavior.SkipLastSnapshot)]
public int CounterNotRestoredOnReconnect { get; set; }
Wywołaj metodę PersistentComponentState.RegisterOnRestoring rejestrowania wywołania zwrotnego w celu imperatywnego kontrolowania sposobu przywracania stanu, podobnie jak PersistentComponentState.RegisterOnPersisting zapewnia pełną kontrolę nad stanem utrwalonego.
Usługa PersistentComponentState działa tylko podczas początkowego ładowania strony oraz nie działa podczas rozszerzonych wewnętrznych zdarzeń nawigacji strony.
Jeśli aplikacja wykonuje pełną (nieulepszoną) nawigację do strony korzystającej z trwałego stanu składnika, utrwalony stan jest udostępniany aplikacji do użycia, gdy stanie się interaktywna.
Jeśli obwód interakcyjny został już ustanowiony i ulepszona nawigacja jest wykonywana do strony korzystającej ze stanu trwałego składnika, stan nie jest udostępniany w istniejącym obwodzie, aby składnik mógł go używać. Brak prerenderingu dla wewnętrznego żądania strony, a usługa PersistentComponentState nie jest świadoma, że dokonano ulepszonej nawigacji. Nie ma mechanizmu dostarczania aktualizacji stanu do komponentów, które są już uruchomione w istniejącym obwodzie. Przyczyną jest to, że Blazor obsługuje tylko przekazywanie stanu z serwera do klienta w czasie inicjowania środowiska uruchomieniowego, a nie po uruchomieniu środowiska uruchomieniowego.
Wyłączenie rozszerzonej nawigacji, które zmniejsza wydajność, ale także pozwala uniknąć problemu ze stanem ładowania PersistentComponentState dla żądań stron wewnętrznych, jest omówione w nawigacji ASP.NET CoreBlazor. Alternatywnie zaktualizuj aplikację do platformy .NET 10 lub nowszej, gdzie Blazor obsługuje obsługę stanu trwałego składnika podczas nawigacji rozszerzonej.
ASP.NET Core