.Net 6 brings application state to blazor webassembly server prerender


Problem of server prerender

Blazor server prerender allows to response not a empty index page of spa to client, but fully rendered page with information like using razor page. Client sees information immediatly and search engine should be happy, however it does not work in that way. The reason how blazor work:

  1. Your page request blazor.js
  2. blazor.js downloads .net runtime and your application dlls
  3. Webassembly runs .net runtime
  4. .Net runs your app

When app is started, it does not know that it was prerendered and call method OnInitialized of your page. Which requests information from backend. While it is waiting for response, blazor shows empty page. In the result, client sees strange blinking page.

.Net 6

You could reinvent the wheel and try to transfer state within page source. For example, json in script section. However, you get different problems like calling js interoper in sync way, because instead your anyway get empty page, or freezing page when you call js in sync way and it blocks ui thread while waiting result.

Fortunately, microsoft adds ability to persist state with new component ` and ComponentApplicationState` service.

Let’s trying use the new component in start template project. All we need to do some changes to allow server prerender and change our FetchData.razor page in that way:

@page "/fetchdata"
@using BlazorPersistedState.Shared
@inject HttpClient Http
@implements IDisposable
@inject ComponentApplicationState ApplicationState

<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;

     protected override async Task OnInitializedAsync()
    {
        ApplicationState.OnPersisting += PersistForecasts;
        if (!ApplicationState.TryTakeAsJson<WeatherForecast[]>("fetchdata", out var data))
        {
            forecasts = await Http.GetFromJsonAsync<WeatherForecast[]>("WeatherForecast");
        }
        else
        {            
            forecasts = data;
        }
    }

    private Task PersistForecasts()
    {
        ApplicationState.PersistAsJson("fetchdata", forecasts);
        return Task.CompletedTask;
    }

    void IDisposable.Dispose()
    {
        ApplicationState.OnPersisting -= PersistForecasts;
    }


}

The main logic here is that if we have any state let’s take this state without extra requests to backend.

if (!ApplicationState.TryTakeAsJson<WeatherForecast[]>("fetchdata", out var data))
{
    forecasts = await Http.GetFromJsonAsync<WeatherForecast[]>("WeatherForecast");
}
else
{            
    forecasts = data;
}

As always, you can find source code of the example here.

Buy Me A Coffee

Related Posts

Avoid reflections of mappers and let Mapster generate mappers for you

Mapster generating tool for onion application

Predict Bitcoin price with ML.net

Live time series coin price predictor with machine learning

Throw exceptions from backend to frontend with blazor

One of advantages of using same code language on both frontend and backend

How to avoid violating of SOLID principles while extending service behaviours

Step by step extending service behaviour with decorator pattern respecting SOLID

Blazor render optimization

Best practices

Must have libraries for blazor

List of best nuget packages

Blazor virtualize component

Lazy loading of big lists. Rendering optimization.

Blazor grpc - comunication optimization

Smaller and faster requests to your backend from blazor wasm

Free database for your blazor app

Don't pay for the cloud

Blazor common error component

Single component for showing errors on any page and component