asp-validation-summary の動作を確認する
現在表示しているページは選択中の表示言語には対応しておりません。
環境
- Visual Studio
-
- Visual Studio 2019
- ASP.NET Core
-
- 3.0
- 3.1
はじめに
ASP.NET Core で入力値の検証エラーを画面に表示させる方法として、asp-validation-summary を使用する方法があるのですが、 指定できるパラメータの違いがよくわからなかったので調べてみました。
指定できる値については以下の3つがあります。
- None
- ModelOnly
- All
これらの違いについてそれぞれどのように動作するか、調べてみた結果以下のようになりました。
事前準備
とりあえず動作を検証するために下準備を行います。 大部分については冗長的に作ってあるので、結果だけ見たい方は記事の後半をご覧ください。
今回の検証はフォームでユーザーを登録する想定をしていますので、ユーザーのビューモデルを作成します。 いろいろ項目を入れていますが、最低1つあれば検証はできるので中身はなんでも構いません。 DataAnnotation によるチェックを行うので Required や StringLength の属性を設定しておきます。 動作の違いを確認するために IsAccepted だけ余分に入れています。
** Models/UserViewModel **
using System;
using System.ComponentModel.DataAnnotations;
namespace ValidationSummaryTest.Models
{
public class UserViewModel
{
[Required]
[StringLength(20)]
public string ID { get; set; }
[Required]
[StringLength(50)]
public string Name { get; set; }
// 省略
[Required]
public bool IsAccepted { get; set; }
}
}
asp-validation-summary の3つの値を調べるため、それぞれのアクションを作ります。 とはいっても asp-validation-summary はビュー側の話なのでそれぞれのアクションの中身はメッセージ以外はすべて同じコードです。
IsAccepted にチェックがついていない場合はエラーを追加しています。 エラーにはモデルとは異なるキーの指定と空のキーを指定したエラーを追加しています。
エラーがなければ正常登録のメッセージを表示させます。
HomeController.cs
public IActionResult ValidateNone() => View();
[HttpPost]
public IActionResult ValidateNone(UserViewModel model)
{
if (model.IsAccepted == false)
{
ModelState.AddModelError("PropertyName1", "プロパティに依存するエラー (None)");
ModelState.AddModelError("", "空のキーエラー (None)");
}
if (ModelState.IsValid == false) return View(model);
ViewData["Message"] = "正常に登録しました。";
return View(model);
}
public IActionResult ValidateModelOnly() => View();
[HttpPost]
public IActionResult ValidateModelOnly(UserViewModel model)
{
if (model.IsAccepted == false)
{
ModelState.AddModelError("PropertyName1", "プロパティに依存するエラー (ModelOnly)");
ModelState.AddModelError("", "空のキーエラー (ModelOnly)");
}
if (ModelState.IsValid == false) return View(model);
ViewData["Message"] = "正常に登録しました。";
return View(model);
}
public IActionResult ValidateAll() => View();
[HttpPost]
public IActionResult ValidateAll(UserViewModel model)
{
if (model.IsAccepted == false)
{
ModelState.AddModelError("PropertyName1", "プロパティに依存するエラー (All)");
ModelState.AddModelError("", "空のキーエラー (All)");
}
if (ModelState.IsValid == false) return View(model);
ViewData["Message"] = "正常に登録しました。";
return View(model);
}
index.cshtml には各テストを行うページへのリンクを追加しています。
index.cshtml
@{
ViewData["Title"] = "Home Page";
}
<div class="text-center">
<h1 class="display-4">Welcome</h1>
<p>Learn about <a href="https://docs.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
</div>
<ul>
<li><a asp-action="ValidateNone">ValidateNone</a></li>
<li><a asp-action="ValidateModelOnly">ValidateModelOnly</a></li>
<li><a asp-action="ValidateAll">ValidateAll</a></li>
</ul>
検証用のユーザー登録ページです。 エラーがあった場合に内容を表示させるパラメータとして asp-validation-summary に None を指定しています。 また、デフォルトのエラーメッセージが表示されるかどうかを確認するために div タグ内に「エラー直接入力」の文章を入れています。
他のコードについてはモデルをベースにスキャフォールディングで自動生成させたコードなので詳しくは説明しません。 (一部手で修正しているところがありますが、今回の検証とは関係ありません)
各入力項目(input タグ)のそばに asp-validation-for 属性が設定されている span タグがありますが、 これは各々の入力項目のエラーメッセージを表示させるためのタグ(属性)であり、 asp-validation-summary に指定したパラメータとは無関係に、エラーがあれば必ずその場所にエラーメッセージが表示されます。
あと、asp-validation-summary はサーバーの検証結果が表示されるので、クライアントの検証処理(_ValidationScriptsPartial)はコメントアウトしています。
ValidateNone.cshtml
@model ValidationSummaryTest.Models.UserViewModel
@{
ViewData["Title"] = "ValidateNone";
}
<h1>ValidateNone</h1>
<h4>UserViewModel</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="ValidateNone">
<div asp-validation-summary="None" class="text-danger">エラー直接入力</div>
<div class="form-group">
<label asp-for="ID" class="control-label"></label>
<input asp-for="ID" class="form-control" />
<span asp-validation-for="ID" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Name" class="control-label"></label>
<input asp-for="Name" class="form-control" />
<span asp-validation-for="Name" class="text-danger"></span>
</div>
@* 省略 *@
<div class="form-group form-check">
<label class="form-check-label">
<input class="form-check-input" asp-for="IsAccepted" /> @Html.DisplayNameFor(model => model.IsAccepted)
</label>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>
@* サーバーのエラーを表示したいのでコメントアウト *@
@*@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}*@
ValidateModelOnly.cshtml のページは asp-validation-summary に ModelOnly を指定しているところ以外は 表示テキストを覗いて ValidateNone.cshtml と同じです。
ValidateModelOnly.cshtml
@model ValidationSummaryTest.Models.UserViewModel
@{
ViewData["Title"] = "ValidateModelOnly";
}
<h1>ValidateModelOnly</h1>
<h4>UserViewModel</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="ValidateModelOnly">
<div asp-validation-summary="ModelOnly" class="text-danger">エラー直接入力</div>
@* 省略 *@
</form>
</div>
</div>
@* 省略 *@
ValidateAll.cshtml のページも asp-validation-summary に All を指定しているところ以外は他とほぼ同じです。
ValidateAll.cshtml
@model ValidationSummaryTest.Models.UserViewModel
@{
ViewData["Title"] = "ValidateAll";
}
<h1>ValidateAll</h1>
<h4>UserViewModel</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="ValidateAll">
<div asp-validation-summary="All" class="text-danger">エラー直接入力</div>
</form>
@* 省略 *@
</div>
</div>
@* 省略 *@
動作確認
None
プログラムを作成したら動作確認をしてみます。ますは asp-validation-summary=None の画面です。
初期表示の状態で「エラー直接入力」と表示されているので、既定のエラーメッセージとしては使えないようです。 Required を設定しているパラメータがあるのでこのまま更新処理を実行してみます。
None の名前の通り、エラーがあっても何も表示されません。 既定のエラーメッセージもそのまま残っているので、直接 None を設定して使う機会はなさそうです。 使う機会があるとすれば、asp-validation-summary に設定する値を動的にして、エラーを表示しない場合は None にするような場面でしょうか。
ModelOnly
asp-validation-summary=ModelOnly を指定した画面です。 検証エラーのサンプルやスキャフォールディングでも出てくるので一番利用場面が多いと思います。
div タグ内に入れていた「エラー直接入力」のテキストは表示されていないので、入れておいても問題なさそうです。
登録処理を行いエラーを表示させてみた状態です。 ここで表示されるメッセージは、div タグ内にあらかじめ入れていた既定のメッセージとサーバー側で発生させたエラーメッセージのみになります。 ただし、サーバー側で空キーのメッセージをいれていない場合は div タグ内のメッセージも出てきませんので注意してください。
サーバー側では2つのエラーメッセージを入れていますが、表示されているのはキーに空文字を入れたエラーのみとなっています。 キーを指定した場合はその名前を持つモデルのプロパティのエラーとして扱われるので、asp-validation-summary の箇所には出てきません。 代わりに同名の asp-validation-for 属性を指定したタグがあればその個所にメッセージが表示されます。
All
asp-validation-summary=All を指定した画面です。
なぜか埋め込んだ「エラー直接入力」のテキストが表示されています。ModelOnly だけ表示されない理由はよくわかりません。 とりあえず All では埋め込みは使えないようです。
そのまま更新処理を行った後の画面です。 全ての入力項目(プロパティ)のエラーメッセージが一覧で表示されます。 各入力項目にもエラーメッセージが表示されるので、もしエラーを纏めて表示させるために All を指定するのであれば、 各入力項目に設定している asp-validation-for 属性は外した方がいいでしょう。
サーバー側で追加したエラーメッセージも表示されています。キーを指定したエラーも表示されていることが確認できます。
まとめ
asp-validation-summary には3つのパラメータがありましたが、 エラーの箇所の分かりやすさや、重複などを省く意味合いでは ModelOnly を使用するのがよいでしょう。 注意点としては asp-validation-summary に表示されるメッセージは空のキーを指定したメッセージのみとなるところです。
ちなみに空のキーには何個でもメッセージは追加できるので、複数のメッセージを表示させるために文字列を結合する必要はありません。
All についてはエラーメッセージを1か所に集めたい場合に使用する、 None についてはなんらかの理由でエラーメッセージを表示させたくないタイミングがあった場合に動的に設定する、 という目的で使用するのがよいでしょう。