ASP.NET Core Blazor WebAssembly - バリデーション【フロントエンド開発入門者向け】

こんにちは！

本記事では、<a href="https://docs.microsoft.com/ja-jp/aspnet/core/blazor/?view=aspnetcore-5.0" target="_blank">ASP.NET Core Blazor</a> (以下 Blazor) のバリデーションについて解説します！


## バリデーションの設定方法

Edit Model に設定した Model のプロパティに対して属性 (Attribute) を定義することでバリデーションを定義できます。ErrorMessage プロパティには、エラーメッセージを定義することができます。

```cs

[Required(ErrorMessage = "姓は必須入力です")]
public string LastName { get; set; }

```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48623/62c3550b-abf1-bceb-d14d-77a0987cfeda.png)



また、様々な検証内容が標準機能で提供されています。

###  標準の属性 (Attribute) 一覧

|  属性  |  検証内容 |
| ---- | ---- |
| Required |  必須入力 |
| StringLength |  文字列の最大の長さを指定  |
| Range |  入力範囲を指定  |
| EmailAddress |  電子メールアドレス形式のチェック  |
| Phone |  電話番号形式のチェック  |
| Url |  URL形式のチェック  |
| RegularExpression | 正規表現でチェック |



### カスタムバリデーション (ビジネスロジックの検証)

ビジネスロジックによるバリデーションは、カスタムバリデーター機能で実現することができます。

下記は、データ登録時に20歳未満の登録を抑制するサンプルとなります。

```cs

@code {

    private CustomValidator customValidator;
    private PeopleModel people = new PeopleModel() { };


    private void HandleValidSubmit()
    {
        customValidator.ClearErrors();

        // ビジネスロジックの検証
        var errors = new Dictionary<string, List<string>>();

        // 20歳未満の場合は登録不可とする。
        int age = DateTime.Now.Year - people.Birthday.Year;
        // 誕生日がまだ来ていない場合、年齢からマイナスする
        if(people.Birthday < DateTime.Now.AddYears(-age))
        {
            age--;
        }
        if(age < 20)
        {
            errors.Add(nameof(people.Birthday),
                new List<string>()
                {
                    "20歳未満の方の登録出来ません。"
                });
        }

        if(errors.Count() > 0)
        {
            customValidator.DisplayErrors(errors);
        }
    }
}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48623/2084ed48-8f38-7487-75c4-870cf4b82d8e.png)


## メッセージの表示方法


### まとめて表示 (ValidationSummary)


ValidationSummary を配置することで検証結果をまとめて表示することが出来ます。

```html
<div style="border : dashed; border-color : orange;">
    <p>検証結果</p>
    <ValidationSummary />
</div>
```





> 複数のモデル(住所、会社情報など)を扱う入力フォームなどで有効な機能として、Model プロパティにモデルを指定すると、指定したモデルのエラー情報のみを表示することができます。
>
>```
><ValidationSummary Model="people" />
>```

			
###	入力項目毎に１つのエラーメッセージを表示 (ValidationMessage)


ValidationMessage コンポーネントを配置することで、対象の入力項目に該当するエラーメッセージのみ表示することが出来ます。


```html
<!-- 名  -->
<p>
    <label class="entry-label">
        名
    </label>
    <div class="entry-input">
        <InputText @bind-Value="people.FirstName"></InputText>
        <ValidationMessage For="@(() => people.FirstName)" />
    </div>
</p>

```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48623/63ec454c-117f-07ae-c640-3aa5372be89b.png)



## サンプル

本記事でバリデーション機能を追加したサンプルの紹介です。

### サンプル動作

![バリデーションサンプル.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48623/6a98828f-04f6-9b7d-6ca7-d7d15d8d1dd5.gif)



### サンプルコード

<b>PeopleModel </b>

```cs

public class PeopleModel
{
    [Required(ErrorMessage = "姓は必須です")]
    public string LastName { get; set; }

    [Required(ErrorMessage = "名は必須です")]
    public string FirstName { get; set; }

    [Required(ErrorMessage = "生年月日は必須です")]
    public DateTime Birthday { get; set; }

    [Required(ErrorMessage = "郵便番号は必須です")]
    public string ZipCode { get; set; }

    [Required(ErrorMessage = "住所は必須です")]
    public string Address { get; set; }

    [Required(ErrorMessage = "電話番号は必須です")]
    [Phone(ErrorMessage = "電話番号の形式に誤りがあります")]
    public string Phone { get; set; }

    [Required(ErrorMessage = "メールアドレスは必須です")]
    [EmailAddress(ErrorMessage = "メールアドレスの形式に誤りがあります")]
    public string Email { get; set; }

}
```

<b>Entry.razor</b>

```html
@page "/PageA"
@using System.Collections.ObjectModel;
@using IgniteUI.Blazor.Controls;
@using BlazorLayoutSample.Models;
@inject IIgniteUIBlazor IgniteUIBlazor
<EditForm Model="@people" OnValidSubmit="@HandleValidSubmit">
    <DataAnnotationsValidator />
    <CustomValidator @ref="customValidator" />
    <div style="display : flex">

        <div style="margin : 30px; width : 30%">


            <h3>入力フォーム</h3>

            <div>


                <!-- 姓 -->
                <p>
                    <label class="entry-label">
                        姓
                    </label>
                    <div class="entry-input">
                        <InputText @bind-Value="people.LastName"></InputText>
                        <ValidationMessage For="@(() => people.LastName)" />
                    </div>
                </p>

                <!-- 名  -->
                <p>
                    <label class="entry-label">
                        名
                    </label>
                    <div class="entry-input">
                        <InputText @bind-Value="people.FirstName"></InputText>
                        <ValidationMessage For="@(() => people.FirstName)" />
                    </div>
                </p>


                <!-- 生年月日 -->
                <p>
                    <label class="entry-label">
                        生年月日
                    </label>
                    <div class="entry-input">
                        <InputDate @bind-Value="people.Birthday"></InputDate>
                        <ValidationMessage For="@(() => people.Birthday)" />
                    </div>
                </p>

                <!-- 郵便番号  -->
                <p>
                    <label class="entry-label">
                        郵便番号
                    </label>
                    <div class="entry-input">
                        <InputText @bind-Value="people.ZipCode"></InputText>
                        <ValidationMessage For="@(() => people.ZipCode)" />
                    </div>
                </p>


                <!-- 住所  -->
                <p>
                    <label class="entry-label">
                        住所
                    </label>
                    <div class="entry-input">
                        <InputText @bind-Value="people.Address"></InputText>
                        <ValidationMessage For="@(() => people.Address)" />
                    </div>
                </p>

                <!-- 電話番号  -->
                <p>
                    <label class="entry-label">
                        電話番号
                    </label>
                    <div class="entry-input">
                        <InputText @bind-Value="people.Phone"></InputText>
                        <ValidationMessage For="@(() => people.Phone)" />
                    </div>
                </p>

                <!-- メールアドレス  -->
                <p>
                    <label class="entry-label">
                        メールアドレス
                    </label>
                    <div class="entry-input">
                        <InputText @bind-Value="people.Email"></InputText>
                        <ValidationMessage For="@(() => people.Email)" />
                    </div>
                </p>
            </div>

        </div>

        <div style="margin : 30px;padding : 12px; border : dashed; border-color : lightgray;">
            <h3>入力内容確認フォーム</h3>

            <p>
                お名前 :  @people.LastName @people.FirstName
            </p>
            <p>
                住所 :  @people.ZipCode @people.Address
            </p>
            <p>
                生年月日 : @people.Birthday.ToString("yyyy/MM/dd")
            </p>
            <div>
                連絡先
                <p>
                    Tel: @people.Phone
                </p>
                <p>
                    Email: @people.Email
                </p>
            </div>


            <div style="margin : 6px;padding : 12px; border : dashed; border-color : orange;">
                <p>検証結果</p>
                <ValidationSummary />
            </div>


        </div>


    </div>
    <div style="margin : 30px;">
        <button type="submit">登録する</button>
    </div>

</EditForm>





<style>
    .entry-label {
        margin-bottom: 0px;
    }

    .entry-input {
    }
</style>


@code {

    private CustomValidator customValidator;
    private PeopleModel people = new PeopleModel() { };


    protected override void OnInitialized()
    {
        DataGridModule.Register(IgniteUIBlazor);
        DatePickerModule.Register(IgniteUIBlazor);
    }


    private void HandleValidSubmit()
    {
        customValidator.ClearErrors();

        // ビジネスロジックの検証
        var errors = new Dictionary<string, List<string>>();

        // 20歳未満の場合は登録不可とする。
        int age = DateTime.Now.Year - people.Birthday.Year;
        // 誕生日がまだ来ていない場合、年齢からマイナスする
        if(people.Birthday < DateTime.Now.AddYears(-age))
        {
            age--;
        }
        if(age < 20)
        {
            errors.Add(nameof(people.Birthday),
                new List<string>()
                {
                    "20歳未満の方は登録出来ません。"
                });
        }

        if(errors.Count() > 0)
        {
            customValidator.DisplayErrors(errors);
        }
    }
}

```



## まとめ 

本記事では、Blazor アプリケーションのバリデーションについて解説しました。

次回の記事では、依存性の注入 (DI)に関する記事を執筆予定です。


## 開発全般に関するご相談はお任せください！

インフラジスティックス・ジャパンでは、各プラットフォームの特別技術トレーニングの提供や、開発全般のご支援を行っています。

「古い技術やサポート終了のプラットフォームから脱却する必要があるが、その移行先のプラットフォームやフレームワークの検討が進まない、知見がない。」

「新しい開発テクノロジーを採用したいが、自社内にエキスパートがいない。日本語リソースも少ないし、開発を進められるか不安。」

「自社のメンバーで開発を進めたいが、これまで開発フェーズを外部ベンダーに頼ってきたため、ツールや技術に対する理解が乏しい。」

「UIを刷新したい。UIデザインやUI/UXに関する検討の進め方が分からない。外部のデザイン会社に頼むと、開発が難しくなるのではないか、危惧している。」

といったご相談を承っています。

お問い合せは<a href="https://jp.infragistics.com/about-us/contact-us#contactform" target="_blank">こちら</a>からお気軽にご相談ください。
![バリデーションサンプル.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48623/93e2a7bd-e7d0-41e8-dbe8-9f277d8bcbc2.gif)