🍣

ASP.NET Core Blazor でクエリパラメーターを駆使して状態保存

2022/05/30に公開

頭の体操みたいな感じなので、多分実プロジェクトではやらないと思うけど、やっちゃったのでメモ。

前提知識

.NET 6 ではクエリパラメーターをコンポーネントのパラメーターに簡単に設定できる機能が追加されているということが前提条件です。

https://zenn.dev/okazuki/articles/blazor-wasm-rc1-queryparam

やりたいこと

Blazor のプロジェクトの新規作成をしたときに作られるカウンターのページのカウントの値を画面遷移をしても保持し続けたい。
データの保存と復元処理は Counter コンポーネントには 書きたくない。DI コンテナにカウンターの値を管理するようなクラスを登録したりせずに、なるべくクエリパラメーターとかを駆使して、その値を何処かに持っておくような形にしたい。

やったこと

まずは、カウンターコンポーネントのカウンターの値をクエリパラメーターから設定できるようにします。

Counter.razor
@page "/counter"
@inject NavigationManager _navigationManager

<PageTitle>Counter</PageTitle>

<h1>Counter</h1>

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

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

@code {
    [SupplyParameterFromQuery(Name = "count")]
    [Parameter]
    public int CurrentCount { get; set; }

    private void IncrementCount()
    {
        CurrentCount++;
        _navigationManager.NavigateTo(
            _navigationManager.GetUriWithQueryParameter("count", CurrentCount),
            replace: true
        );
    }
}

次に App.razor の Router コンポーネントの画面遷移時のイベントの OnNavigateAsync メソッドで画面遷移の URL を見て count パラメーターの値を保存・復元するような処理を追加します。

App.razor
@using Microsoft.AspNetCore.WebUtilities
@inject NavigationManager _navigationManager
<Router AppAssembly="@typeof(App).Assembly" OnNavigateAsync="OnNavigateAsync">
    <Found Context="routeData">
        <RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
        <FocusOnNavigate RouteData="@routeData" Selector="h1" />
    </Found>
    <NotFound>
        <PageTitle>Not found</PageTitle>
        <LayoutView Layout="@typeof(MainLayout)">
            <p role="alert">Sorry, there's nothing at this address.</p>
        </LayoutView>
    </NotFound>
</Router>

@code {
    // とりあえずカウンターの値はここに保存しておく。
    private int _count = 0;
    private Task OnNavigateAsync(NavigationContext context)
    {
        if (context.Path.StartsWith("counter?"))
        {
            // count パラメーター付きの場合は値を保存
            var uri = _navigationManager.ToAbsoluteUri(context.Path);
            var parameters = QueryHelpers.ParseQuery(uri.Query); // Microsoft.AspNetCore.WebUtilities パッケージが必要
            int.TryParse(parameters["count"].ToString(), out _count);
        }
        else if(context.Path == "counter" && _count != 0)
        {
            // counter ページへのパラメーター無しの遷移の場合は保存した値をパラメーターに足す
            var path = _navigationManager.GetUriWithQueryParameter("count", _count);
            _navigationManager.NavigateTo(path, replace: true);
        }

        return Task.CompletedTask;
    }
}

こうすると、画面遷移時に count パラメーター付きの時は、その値を App クラスの _count フィールドに保存しつつ、パラメーターの無い counter ページの遷移時には必要に応じて count パラメーターをつけるようにしています。

とりあえず頭の体操的な感じですね。

Microsoft (有志)

Discussion