Skip to content

PersistentComponentState: large state will crash the client, unable to recover #44935

@Bouke

Description

@Bouke

Is there an existing issue for this?

  • I have searched the existing issues

Describe the bug

I was debugging an issue with a page that rendered, but started showing the "reconnecting" dialog after ~20 seconds or so. There was no error server-side and the client-side contained rather unhelpful traceback:

[Error] [2022-11-08T09:44:35.259Z] Error: Error: Circuit host not initialized.
log (blazor.server.js:1:115822)
(anonymous function) (blazor.server.js:1:122515)
asyncFunctionResume
(anonymous function)
promiseReactionJobWithoutPromise
promiseReactionJob

After some investigation I've found a similar issue with this message: #44280 (comment). This is a severe problem in our situation, as we don't know beforehand the pre-rendered size of certain data. The failure mode here is completely wrong: when you go over the limit, the client will fail to initialize and you have no way of detecting this nor recovering.

Expected Behavior

State preservation should fail server-side when trying to persist data that will be over the limit.

Steps To Reproduce

@page "/weather-forecast-preserve-state"
@implements IDisposable
@using BlazorSample.Shared
@inject IWeatherForecastService WeatherForecastService
@inject PersistentComponentState ApplicationState

<PageTitle>Weather Forecast</PageTitle>

<h1>Weather forecast</h1>

<p>This component demonstrates fetching data from the server.</p>

@if (forecasts == null)
{
    <p><em>Loading...</em></p>
}
else
{
    <table class="table">
        <thead>
            <tr>
                <th>Date</th>
                <th>Temp. (C)</th>
                <th>Temp. (F)</th>
                <th>Summary</th>
            </tr>
        </thead>
        <tbody>
            @foreach (var forecast in forecasts)
            {
                <tr>
                    <td>@forecast.Date.ToShortDateString()</td>
                    <td>@forecast.TemperatureC</td>
                    <td>@forecast.TemperatureF</td>
                    <td>@forecast.Summary</td>
                </tr>
            }
        </tbody>
    </table>
}

@code {
    private WeatherForecast[] forecasts = Array.Empty<WeatherForecast>();
    private PersistingComponentStateSubscription persistingSubscription;

    protected override async Task OnInitializedAsync()
    {
        persistingSubscription = 
            ApplicationState.RegisterOnPersisting(PersistForecasts);

        if (!ApplicationState.TryTakeFromJson<WeatherForecast[]>(
            "fetchdata", out var restored))
        {
            forecasts = 
                await WeatherForecastService.GetForecastAsync(DateTime.Now);
        }
        else
        {
            forecasts = restored!;
        }
    }

    private Task PersistForecasts()
    {
        ApplicationState.PersistAsJson("fetchdata", Enumerable.Repeat(forecasts.First(), 10_000).ToArray());

        return Task.CompletedTask;
    }

    void IDisposable.Dispose()
    {
        persistingSubscription.Dispose();
    }
}

Exceptions (if any)

No response

.NET Version

6.0.402

Anything else?

No response

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions