ASP.NET Coreでフォーム入力を検証する方法!ModelStateの使い方を初心者向けに徹底解説
生徒
「C#を使ってWebアプリを作っているのですが、ユーザーが文字を入力する画面で、空っぽのままボタンを押されたり、おかしな数字を入れられたりするのを防ぎたいです。」
先生
「それはフォーム入力の検証という仕組みで解決できますよ。ASP.NET CoreにはModelStateという、入力されたデータが正しいかどうかを自動でチェックしてくれるとても便利な道具が用意されています。」
生徒
「モデるすてーと、ですか?難しそうですが、パソコンの操作に慣れていない私でも仕組みを理解してプログラムを書くことができますか?」
先生
「大丈夫です。入力データの健康診断のようなものだと考えれば簡単です。具体的な仕組みと書き方を、基礎から順番に見ていきましょう!」
1. フォーム入力の検証とは?
Webアプリケーションを開発するとき、ユーザーが文字や数字を入力する画面のことをフォームと呼びます。例えば、会員登録の画面で名前やメールアドレス、パスワードを入力する欄がこれに該当します。
ユーザーは常に正しいデータを入力してくれるとは限りません。名前の欄を空欄のまま送信ボタンを押してしまったり、年齢を入れる欄に文字を入力してしまったりすることがあります。このような不適切なデータがそのままプログラムに送られると、システムが予期せぬエラーを起こして止まってしまったり、データベースに変なデータが保存されてしまったりする原因になります。
そこで、送られてきたデータが開発者の決めたルールに合格しているかどうかを調べる作業が必要になります。この仕組みのことをフォーム入力の検証、またはバリデーションと呼びます。検証を行うことで、安全で使いやすいシステムを作ることができるようになります。
2. ModelStateの基本的な仕組みと役割
C#のWebアプリ開発の土台であるASP.NET Coreには、入力データの検証を簡単に行うためのModelStateという仕組みが備わっています。
ユーザーが画面のボタンを押してデータを送信すると、システムは送信された内容をC#のプログラムで扱いやすい形に変換します。この変換と同時に、データが事前に決めたルールを守っているかどうかを自動的にチェックし、その結果のメモを保存します。このチェック結果のメモ帳のような役割を果たすのが、ModelStateです。
プログラムの中では、このメモ帳に不合格の印がついているかどうかを確認するだけで、入力されたデータが正しいかどうかを判断することができます。開発者が一つずつ手作業で文字の長さを数えたり、空っぽかどうかを調べるコードを書く必要がないため、書き間違いを減らし、すっきりとしたプログラムを作成することができます。
3. データ注釈属性を使った検証ルールの決め方
データが正しいかどうかを判定するためには、あらかじめ「この項目は必須です」「この項目は何文字以内で入力してください」という規則を定めておく必要があります。C#では、データを表現するクラスのプロパティに対して、データ注釈属性と呼ばれる特別な目印をつけることで、この規則を設定します。
代表的な目印には、入力を必須にする属性や、文字の長さを制限する属性などがあります。この目印をつけておくだけで、システムがデータを読み込む際に自動的に内容を検査し、不適切なデータがあればModelStateにエラー内容を記録してくれます。まずは、ユーザーが入力するデータを表現するための簡単なクラスの書き方を見てみましょう。
using System.ComponentModel.DataAnnotations;
public class UserForm
{
[Required(ErrorMessage = "お名前は必ず入力してください。")]
public string Name { get; set; }
[Range(1, 120, ErrorMessage = "年齢は1から120の間で入力してください。")]
public int Age { get; set; }
}
上記のプログラムでは、名前の項目に必須入力を意味する属性をつけ、年齢の項目には有効な数値の範囲を指定する属性をつけています。このように設定することで、指定した条件に合わないデータが送られてきた場合に、自動的にエラーとして扱われるようになります。
4. コントローラーでのエラー判定の具体的な記述方法
データに目印をつけたら、次は画面からのデータを受け取るコントローラーというプログラムの中で、検査結果を確認する処理を書きます。ここで登場するのが、ModelStateが持っている状態を確認する仕組みです。
ModelStateには、すべての項目がルールに合格したかどうかを真偽値で教えてくれるプロパティがあります。これを利用して条件分岐を行い、合格であれば次の登録処理に進み、不合格であればエラーメッセージを添えてもう一度入力画面を表示する、という流れを作ります。具体的なコントローラーの処理は、以下のように記述します。
using Microsoft.AspNetCore.Mvc;
public class UserController : Controller
{
[HttpGet]
public IActionResult Register()
{
return View();
}
[HttpPost]
public IActionResult Register(UserForm form)
{
if (!ModelState.IsValid)
{
return View(form);
}
return RedirectToAction("Success");
}
}
このプログラムでは、状態を確認するプロパティの前に否定を意味する記号をつけることで、「もし検証結果が合格ではなかったら」という条件を作っています。不合格だった場合は、ユーザーが入力した内容を保持したまま、同じ入力画面をもう一度表示するように指示しています。これにより、ユーザーは最初からやり直すことなく、間違えた部分だけを修正できるようになります。
5. 画面にエラーメッセージを表示するための設定
コントローラー側でエラーを検知して画面を再表示しても、画面上にどこが間違っているのかが表示されなければ、ユーザーは何を修正すればよいのか分かりません。そこで、HTMLを表示するためのファイルに、エラーメッセージを画面に出力するための専用の記述を追加します。
ASP.NET Coreでは、独自の拡張タグを使用することで、特定の項目に関するエラーメッセージを自動的にHTMLとして出力することができます。これにより、デザインを崩さずに分かりやすい警告を表示させることができます。以下は、入力画面を作成するためのHTMLファイルの記述例です。
@model UserForm
<form asp-action="Register" method="post">
<div class="mb-3">
<label>お名前</label>
<input asp-for="Name" class="form-control" />
<span asp-validation-for="Name" class="text-danger"></span>
</div>
<div class="mb-3">
<label>年齢</label>
<input asp-for="Age" class="form-control" />
<span asp-validation-for="Age" class="text-danger"></span>
</div>
<button type="submit" class="btn btn-primary">送信する</button>
</form>
この画面ファイルでは、特定の属性を使用することで、C#のクラスで定義したエラーメッセージと入力欄を紐づけています。もし名前が空欄のまま送信された場合、該当する箇所に自動的にエラー文言が挿入され、文字が赤く表示される仕組みになります。
6. 文字数制限をかけるための応用ルール
必須入力や数値の範囲だけでなく、実際の開発では「パスワードは8文字以上にしてください」や「自己紹介は200文字以内にしてください」といった、文字の長さを制限したい場面が頻繁にあります。そのような場合にも、別の新しい目印をプロパティにつけることで対応が可能です。
文字数の制限を行うことで、データベースの容量を超えてしまうような長文の入力を防いだり、短すぎる不正な入力をブロックしたりすることができます。新しいルールを適用したデータ管理用のクラスを作成してみましょう。
using System.ComponentModel.DataAnnotations;
public class AccountForm
{
[Required(ErrorMessage = "ユーザーIDは必須項目です。")]
[StringLength(15, MinimumLength = 5, ErrorMessage = "ユーザーIDは5文字以上15文字以内で入力してください。")]
public string UserId { get; set; }
[Required(ErrorMessage = "パスワードは必須項目です。")]
[MinLength(8, ErrorMessage = "パスワードは8文字以上で入力してください。")]
public string Password { get; set; }
}
このクラスでは、文字数の最大値と最小値を同時に指定できる属性や、最低限必要な文字数のみを指定する属性を使用しています。一つの項目に対して複数の目印を重ねてつけることもできるため、非常に柔軟なルール作りが可能となっています。
7. 文字列の形式を判定する高度な検証方法
さらに高度な検証として、入力された文字が特定の形式に沿っているかどうかを調べたい場合があります。例えば、メールアドレスの形式として正しいか、電話番号の数字の並びになっているか、といった判定です。これらを手作業で判別するのは複雑ですが、専用の形式チェック用の属性を使うことで簡単に実現できます。
これにより、メールアドレスの入力欄にただの文字列が入力されるようなミスを防ぐことができます。形式チェックを組み込んだプログラムの例を確認してみましょう。
using System.ComponentModel.DataAnnotations;
public class ContactForm
{
[Required(ErrorMessage = "メールアドレスを入力してください。")]
[EmailAddress(ErrorMessage = "正しいメールアドレスの形式で入力してください。")]
public string Email { get; set; }
[Phone(ErrorMessage = "正しい電話番号の形式で入力してください。")]
public string PhoneNumber { get; set; }
}
このように、あらかじめ用意されている形式検証用の属性を活用することで、複雑な文字パターンの解析を行うことなく、精度の高い入力チェック機能を実装することができます。ユーザーが間違った形式で入力した場合は、自動的にエラーのメモが作成されます。
8. 独自の検証エラーをプログラムで追加する方法
属性をつけるだけの自動チェックは大変便利ですが、それだけでは解決できない複雑な条件もあります。例えば、「すでにデータベースに登録されているユーザー名は使えない」といった、外部のデータと照らし合わせる必要がある場合です。
このような業務上の特別なルールを判定する場合は、自動チェックの後に、コントローラーの中で独自のチェック処理を記述します。もし問題が見つかった場合は、手動でModelStateにエラー内容を追加することができます。その方法を示したプログラムを見てみましょう。
[HttpPost]
public IActionResult CreateAccount(AccountForm form)
{
if (form.UserId == "admin")
{
ModelState.AddModelError("UserId", "このユーザーIDは管理用のため使用できません。");
}
if (!ModelState.IsValid)
{
return View(form);
}
return RedirectToAction("Dashboard");
}
このプログラムでは、特定の名前が入力された場合に、専用の命令を使って手動でエラーメッセージを登録しています。これにより、自動検証をすり抜けたデータに対しても、独自のルールで厳しくチェックを行い、安全性をさらに高めることができます。
9. 検証が動作したときの実際の動きと結果の確認
これまでに解説した仕組みがすべて組み合わさることで、Webアプリの入力チェック機能が完成します。ユーザーが画面の送信ボタンをクリックしたとき、内部のプログラムがどのように動き、どのような結果が出力されるのか、その流れを整理しておきましょう。
例えば、必須項目を空欄のままにして送信ボタンを押すと、プログラムは登録処理を途中で中断し、再度入力画面を生成します。その際、自動的にエラー情報が引き継がれ、画面の指定された位置にメッセージが配置されます。最終的にユーザーのブラウザに出力される結果のイメージは以下のようになります。
お名前: [ フォームの入力欄 ]
お名前は必ず入力してください。(※赤い文字で表示される)
年齢: [ フォームの入力欄 ]
年齢は1から120の間で入力してください。(※赤い文字で表示される)
このように、間違ったデータを受け付けない堅牢な壁を作ることで、システム全体の品質を保つことができます。ModelStateは、開発者が最小限のコードを書くだけで、ユーザーにとっても親切な画面案内を提供する、ASP.NET Core開発において欠かせない重要な基礎知識です。