🔍

Blazorバリデーションの基本:DataAnnotationsを使った実装

に公開

Blazorで入力フォームを作っているとき、バリデーションロジックをどこに書いていますか? 先日、私はつい「ボタンが押されたときに、コードビハインド(C#側)で if 文を並べてエラーメッセージを自作する」実装をしてしまいました。 動くには動きますが、DataAnnotations を活用することで、エラーメッセージの表示・非表示を状態に応じて自動で切り替えられるため、よりBlazorらしい宣言的な実装[1]が可能です。

そこで今回は、基本となる3つのコンポーネントの役割と使い方を整理して紹介します。

対象読者

  • Blazorでフォーム開発を始めたばかりの方
  • コードビハインドにバリデーションをゴリゴリ書いてしまい、スマートに書き直したい方
  • 標準コンポーネント(ValidationSummary など)の使い分けを知りたい方

この記事のゴール

  • DataAnnotationsValidator を使った宣言的なバリデーションを実装できる
  • ValidationSummary と ValidationMessage を適切に併用できる

動作環境・前提条件

  • Visual Studio 2022
  • .NET 8
  • プロジェクト構成: 「Interactivity location」を Global に設定(App.razor の Routes に @rendermode が付与されている状態)

サンプルコード

@page "/registration"
@using System.ComponentModel.DataAnnotations

<h3>ユーザー登録</h3>

<EditForm Model="@_model" OnValidSubmit="HandleValidSubmit">
    @* (1) DataAnnotationsの属性をスキャンして検証を実行するエンジン *@
    <DataAnnotationsValidator />

    @* (2) エラーメッセージを上部にまとめて表示(一覧性が高い) *@
    <ValidationSummary />

    <div class="mb-3">
        <label>名前:</label>
        <InputText @bind-Value="_model.Name" class="form-control" />
        @* (3) 項目ごとのエラーメッセージを表示(直感的) *@
        <ValidationMessage For="@(() => _model.Name)" />
    </div>

    <div class="mb-3">
        <label>メールアドレス:</label>
        <InputText @bind-Value="_model.Email" class="form-control" />
        <ValidationMessage For="@(() => _model.Email)" />
    </div>

    <button type="submit" class="btn btn-primary">登録</button>
</EditForm>

@code {
    private RegistrationModel _model = new();

    private void HandleValidSubmit()
    {
        // バリデーションを通過したときのみ呼ばれる
    }

    private class RegistrationModel
    {
        [Required(ErrorMessage = "名前は必須です")]
        [StringLength(10, ErrorMessage = "名前は10文字以内で入力してください")]
        public string Name { get; set; } = string.Empty;

        [Required(ErrorMessage = "メールアドレスは必須です")]
        [EmailAddress(ErrorMessage = "正しいメールアドレスの形式で入力してください")]
        public string Email { get; set; } = string.Empty;
    }
}

実際の画面

バリデーションエラーが表示されたフォームのGIFアニメーション

3つの重要コンポーネントの役割

なぜコードビハインドで書くよりも、これらのコンポーネントを使うべきなのでしょうか。

DataAnnotationsValidator

これは「検証の実行エンジン」です。 EditForm の中に置くだけで、モデルに付与された [Required] などの属性を自動的に解析し、フォーム全体の検証状態(EditContext)を管理してくれます。 そのため自分で if 文を書く必要がなくなります。

ValidationSummary と ValidationMessage の使い分け

今回のサンプルでは両方を併用しています。

  • ValidationSummary: 今回はフォームの上部に「何が足りないか」をリストアップしました。 入力項目が多い場合、どこでエラーが起きているか一目で把握するのに役立ちます。

  • ValidationMessage: 今回は各入力フィールドのすぐ下に表示します。 ユーザーが「どの項目を修正すべきか」を迷わせないために必須の要素です。

まとめ

今回のバリデーションのポイントは、「自分でチェック処理を書かずに、フレームワークの仕組みに乗っかること」でした。今回紹介した3つのコンポーネントを組み合わせるだけで、UIの状態管理と検証ロジックをきれいに分離できます。

DataAnnotationsValidator: 属性([Required]など)を読み取り、検証を自動化するエンジン。

ValidationSummary: フォーム全体の不備をリストアップし、ユーザーに全体像を伝える。

ValidationMessage: 各入力項目のすぐ横で、直感的なフィードバックを与える。

これらの標準コンポーネントで「宣言的」に解決できないかを検討することで、C#側のコード(if文など)で制御する必要がなくなり、Blazorらしい実装になります。

参考

より詳細な仕様は、ASP.NET Core Blazor のフォームの検証を確認してください。

脚注
  1. 宣言的な実装とは、UIの更新手順を直接書くのではなく、データの状態に応じた「あるべき画面の姿」をRazor構文で定義し、実際の更新はフレームワークに委ねる実装方式を指します。「宣言的」という文言は、Reactの「宣言的」に関する以下の定義を念頭に置いて使いました。declarative: you tell React what to render in your component’s logic, and React will figure out how best to display it to your user. ↩︎

Discussion