🐱‍👤

.NET 6 の Blazor のコンポーネントでクエリ パラメーターを使うのが簡単になりました

2021/09/26に公開

内容としては、ここらへんで紹介されているものになります。

https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-6-preview-7/

https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-6-rc-1/

Blazor のコンポーネントで URL のクエリ パラメーターを使うのが凄く簡単になりました。今までは自分でクエリパラメーターを取得するような処理を書かないといけなかったのですが、.NET 6 では基本的にこの機能で賄えるようになると思います。

因みに今までクエリパラメーター使おうと思うと大体以下のような感時にする必要がありました。クエリパラメーターをパースしてくれるライブラリを参照に追加(例えば Microsoft.AspNetCore.WebUtilities) して、コンポーネントの OnInitialized メソッドでパラメーターを解析して頑張る!

ちょっとやってみましょう。Blazor WebAssembly のプロジェクトを新規作成して Index.razor に実装していきます。

Index.razor
@page "/"
@using Microsoft.AspNetCore.WebUtilities
@inject NavigationManager NavigationManager

<PageTitle>Index</PageTitle>

<h1>Hello, world!</h1>

<span>@Message</span>

@code {
    [Parameter]
    public string? Message { get; set; }

    protected override void OnInitialized()
    {
        var uri = NavigationManager.ToAbsoluteUri(NavigationManager.Uri);
        if (QueryHelpers.ParseQuery(uri.Query).TryGetValue("message", out var message))
        {
            Message = message;
        }
    }
}

そんなにコードとしては大変じゃないですが、複数個になってくると同じようなコードをコピペしないといけなかったり、コピペが不要になるような何らかの仕組みを自分で実装する必要があります。ちょっとメンドクサイ。

.NET 6 では [SupplyParameterFromQuery] という属性をプロパティにつけるだけでクエリパラメーターからいい感じに値をセットしてくれるようになります。いいね!

Index.razor
@page "/"

<PageTitle>Index</PageTitle>

<h1>Hello, world!</h1>

<span>@Message</span>

@code {
    [SupplyParameterFromQuery]
    [Parameter]
    public string? Message { get; set; }
}

凄くすっきりしました。

パラメーターに状態を保存したい…

さて、クエリパラメーター繋がりで機能をもう1つ。Blazor で画面がリフレッシュされたり、画面遷移したあとのブラウザーバック時も状態を保持したいようなケースではクエリパラメーターに状態を保持することで実現できます。
URL さえ覚えてたら状態が復元できるというお手軽さなので、これで出来るならこれを使うのが個人的にはいいのかなと思ってます。その他にはローカルのブラウザーのセッション ストレージやローカル ストレージなどのような場所に永続化する方法や、Web API ごしにサーバーサイドの DB などに保存する方法があります。もしくは、これらの合わせ技で状態を保存することになります。

今回 NavigationManagerGetUriWithQueryParameterGetUriWithQueryParameters というメソッドが追加されています。これは引数に渡したパラメーターをクエリパラメーターに設定した URL を返すメソッドです。最初のが1つだけパラメーターをつけるもので、2 つ目のメソッドは IReadOnlyDictionary<string, object?> を受け取って複数のパラメーターをつけることが出来ます。

それに加えて NavigationManager クラスの NavigateTo メソッドに replace というパラメーターが追加されました。これを true にすると現在の URL を純粋に置き換えるという動きになります。ブラウザーの履歴上も置き換え前の現在の URL は無かったことになって新しい URL が今の URL になります。

これを組み合わせると URL にコンポーネントの状態を保存しておくということが簡単に実装できます。やってみましょう。

Index.razor
@page "/"
@inject NavigationManager NavigationManager

<PageTitle>Index</PageTitle>

<h1>Hello, world!</h1>

<span>@Message</span>

<div>
    <button @onclick="UpdateMessageAndStore">現在時刻でメッセージを更新!</button>
</div>

@code {
    [SupplyParameterFromQuery]
    [Parameter]
    public string? Message { get; set; }

    private void UpdateMessageAndStore()
    {
        Message = DateTime.Now.ToString();
        // 現在のブラウザーの URL を新しいものに置き換え!
        NavigationManager.NavigateTo(
            // URL は現在のページの URL にクエリパラメーターを設定したもの
            NavigationManager.GetUriWithQueryParameter(nameof(Message), Message),
            replace: true
        );
    }
}

ボタンを押すと Message プロパティを現在時刻で更新します。その後、URL に Message の値をセットしたもので現在の URL を置き換えます。

実行結果は以下のようになります。ボタンを押したら URL が書き換わっている点と、一度別のページにいったあとにブラウザーの戻るボタンでもどっても状態が保持されていることが確認できると思います。

まとめ

ということで、今回は細かいところですが段々と痒い所の機能改善に取り組むことが出来るようになってきたなぁと感じた機能を紹介しました。

.NET 6 のリリースまで後一か月とちょっとで待ち遠しいですね。

Microsoft (有志)

Discussion