🐱

BlazorでWeb Storageを利用して一時的にデータを保存する方法

2022/01/19に公開

この記事では、BlazorでWeb Storageを利用する方法について解説したいと思います。
ユーザーがリロードすると画面上の情報が失われてしまいます。その際に、データを一時的に保存しておき、状態を維持する方法を見ていきたいと思います。

本記事はQiitaのミラーです。
https://qiita.com/yoshi1220/items/0112ecc7275c9e290dc0

Web Storageとは?

HTML5で導入されたブラウザーにKey-Value形式でテキストデータを保存できる仕組みです。ブラウザーにデータを保管する仕組みとしてはCookieがありますが、Cookieよりも保存容量が大きく、常にHttp Headerで送信されるわけではなく、必要なときにだけ取り出せます。
sessionStroageとlocalStorageの2種類があり、目的に応じて使い分けができます。

  • sessionStorage
    ブラウザーのタブ単位でデータを保存できます。タブを再読込してもデータは維持されますが、タブかブラウザーを閉じると、データは失われます。

  • localStorage
    ブラウザー単位でデータを保存でき、タブやブラウザー本体を閉じてもデータが維持されます。再度ブラウザーを起動するとデータを再読み込みできます。

Blazor ServerでWeb Storageを利用する方法

まずは、Blazor ServerでWeb Storageを利用する方法をご紹介したいと思います。
Blazor ServerではMicrosoftが提供している、「ASP.NET Core で保護されたブラウザー ストレージ」を利用することで、簡単にデータを暗号化して保存できます。

sessionStorageの場合

CounterSessionStorage.razor
@page "/countersession"
@using Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage
@inject ProtectedSessionStorage ProtectedSessionStore

<PageTitle>Counter</PageTitle>

<h1>Counter</h1>

@if (isConnected)
{
    <p>Current count: <strong>@currentCount</strong></p>
    <button @onclick="IncrementCount">Increment</button>
}
else
{
    <p>Loading...</p>
}

@code {
    private int currentCount;
    private bool isConnected;

    /// <summary>
    /// コンポーネントのレンダリングが完了した後に呼び出されます
    /// </summary>
    /// <param name="firstRender"></param>
    /// <returns></returns>
    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            isConnected = true;
            await LoadStateAsync();
            StateHasChanged();
        }
    }

    private async Task LoadStateAsync()
    {
        var result = await ProtectedSessionStore.GetAsync<int>("count");
        currentCount = result.Success ? result.Value : 0;
    }

    private async Task IncrementCount()
    {
        currentCount++;
        await ProtectedSessionStore.SetAsync("count", currentCount);
    }
}

Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorageを読み込むことにより、ProtectedSessionStorageを利用できます。
sessionStorage、localStorageは、プリレンダリング中に利用できないため、OnInitializedAsyncではなく、OnAfterRenderAsyncに画面読み込み時のデータ読み取り処理を記述します。
これで画面をリロードした際も、同じタブ内であればデータを保存し、再読み込みできます。

また、データが暗号化されていることも、開発者ツールから確認できます。
image.png

localStorageの場合

ProtectedSessionStorageをProtectedLocalStorageに変更するだけです。
localStorageの場合は、ブラウザーを終了してもデータが保存されます。再度ブラウザーを起動すれば保存した値を読み込むことが可能です。localStorageに保存したデータは、有効期限がないため、システムから削除するか、ユーザーが自分で削除しない限りデータが残り続けることに注意してください。

localStorageの場合も、同様にデータが暗号化されます。

Blazor WebAssemblyでWeb Stroageを利用する方法

Blazor WebAssemblyの場合は、Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorageを利用できないため、サードパーティ製のライブラリを利用した例をご紹介します。

今回は、Blazoredというライブラリを使ってみます。(https://github.com/Blazored)
導入はNugetから、Blazored.SessionStorage、Blazored.LocalStorageを検索すると見つかります。
image.png

sessionStorageの場合

Blazored.SessionStorageを読み込み、builderにサービスを登録します。これで各Razorコンポーネントから利用できます。

Program.cs
using Blazored.SessionStorage;

...

builder.Services.AddBlazoredSessionStorage();

await builder.Build().RunAsync();
Counter.razor
@page "/counter"
@inject Blazored.SessionStorage.ISessionStorageService sessionStorage

<PageTitle>Counter</PageTitle>

<h1>Counter</h1>

<p role="status">Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

@code {
    private int currentCount = 0;

    protected override async Task OnInitializedAsync()
    {
        currentCount = await sessionStorage.GetItemAsync<int>("count");
    }

    private void IncrementCount()
    {
        currentCount++;
        sessionStorage.SetItemAsync("count", currentCount);
    }
}

Blazor Serverの時と同様にデータの保存、読み込みができます。(Blazoredを利用した場合は、OnInitializedAsyncでも読み込みが可能なようです。)
ただし、そのままではデータの暗号化はされないので、ユーザーが自由にデータの中身を確認できる点については注意してください。

image.png

localStorageの場合

読み込むライブラリが違うだけで、ほとんど同じように実装できます。

Program.cs
using Blazored.LocalStorage;
using BlazorWasmBrowserStorage1;
using Microsoft.AspNetCore.Components.Web;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;

var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("#app");
builder.RootComponents.Add<HeadOutlet>("head::after");

builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
builder.Services.AddBlazoredLocalStorage();

await builder.Build().RunAsync();
Counter.razor
@page "/counter"
@inject Blazored.LocalStorage.ILocalStorageService localStorage

<PageTitle>Counter</PageTitle>

<h1>Counter</h1>

<p role="status">Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

@code {
    private int currentCount = 0;

    protected override async Task OnInitializedAsync()
    {
        currentCount = await localStorage.GetItemAsync<int>("count");
    }

    private void IncrementCount()
    {
        currentCount++;
        localStorage.SetItemAsync("count", currentCount);
    }
}

まとめ

BlazorでWeb Storageを利用する方法をご紹介しました。
ページ遷移でデータを保持するだけであれば、サービスをDIコンテナにScopedで登録することでも対応可能ですが、ページリロード時にはデータが消失します。その場合でもデータを保持したい場合には、Web Storageを利用をご検討ください。
皆様のご参考になれば幸いです。

参考サイト

この記事は以下の情報を参考にして執筆しました。

Discussion