WebSurfer's Home

トップ > Blog 1   |   ログイン
APMLフィルター

int 型プロパティの検証、エラーメッセージ (MVC5)

by WebSurfer 2019年3月24日 16:06

ASP.NET MVC で、モデルのプロパティが int 型の場合の検証とエラーメッセージに関する注意点を書きます。

NULL 許容参照型がデフォルトで有効になっている ASP.NET Core 6.0+ の場合については別の記事「整数型プロパティの検証、エラーメッセージ (CORE)」を見てください。

検証��エラーメッセージ

モデルのプロパティが int 型の場合、クライアント側の検証を有効にしておけば、RequiredAttribute, RegularExpressionAttribute は付与しなくても input 要素には data-val-required="xxx フィールドが必要です。", data-val-number="フィールド xxx には数字を指定してください。" という属性が付与され、入力に応じてそれらのエラーメッセージが表示されます。

プロパティに RequiredAttribute が付与され ErrorMessage が設定されている場合は、data-val-required 属性に設定される文字列が ErrorMessage に置き換わります。(ちなみに、プロパティが int? 型の場合は data-val-required 属性そのものが付与されません)

上記は TextBoxFor, EditorFor いずれを使っても同じです。

ただし、EditorFor を使うと input 要素の type 属性が "number" となるので、それによりブラウザ依存の動きが出るのに要注意です。(TextBoxFor を使った場合は type 属性は "text" となります)

input 要素の type 属性が "number" となると、例えば、Chrome は数字以外の入力は受け付けなくなりますが、IE11 は最初の文字が数字であれば後に続く文字は何でも入力できてしまうという違いが出ます。

さらに、プロパティに RegularExpressionAttribute を追加して数字か否かをチェックするようにしても、input 要素の type 属性が "number" となっていると無視されます。

その場合動きはブラウザ依存になり、"1x" というような入力を受け付ける IE11 では data-val-number 属性に設定されたメッセージが、Firefox では data-val-required 属性に設定されたメッセージが表示されます。Chrome は "1x" というような文字は入力できませんが、"1..." という文字列は受け付けるので、その場合は Firefox と同様に data-val-required 属性に設定されたメッセージが表示されます。

EditorFor ではなく TextBoxFor を使えば input 要素の type 属性は "text" となって、RegularExpressionAttribute による検証が行われ、検証 NG の場合は ErrorMessage に設定したメッセージが表示されます。

input 要素の type 属性が "number" となることによりブラウザ依存の動きとなって期待と異なるエラーメッセージが出るのを避けるためには以下の対応が必要です:

  1. TextBoxFor を使って input 要素の type 属性が "text" となるようにし、さらに
  2. RegularExpressionAttribute で数字か否かの検証を行う。  

以上はクライアント側での検証の話です。サーバー側での検証によるエラーメッセージは上記とは異なります。上の画像の「価格2 (int)」のエラーメッセージを見てください。

クライアント側での検証を無効にして "2000x" という文字列を送信していますが「値 '2000x' は 価格2 (int) に対して無効です。」というエラーメッセージが出ています。

それは EditorFor (type="number") でも TextBoxFor (type="text") でも同じで、数字として不正な文字が混ざって POST されると、モデルバインディングの際 int 型にパースできないということで、RegularExpressionAttribute による検証が行われる前に検証 NG となって、そのエラーメッセージが出るようです。

RegularExpressionAttribute の ErrorMessage に設定したメッセージが表示されて欲しいのですが、int 型にパースできない文字列が POST されては何ともならないようです。ただし、このエラーメッセージを書き換える方法はあります。

マイクロソフト公式解説書「プログラミング ASP.NET MVC」の p186「エラーメッセージを制御する」に書いてあったことですが、ModelStateDictionary に含まれる ModelState は同じ Key でマージした方に上書きされます。具定例は以下のコードの通りです。上の画像の「ID (int)」がこのコードによる書き換え結果です。

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult WankumaEdit(Keiyaku model)
{
  if (ModelState.IsValid)
  {
    // DB の編集処理
    return RedirectToAction("Index");
  }

  // デバッグ用
  ModelStateDictionary dictionary = ModelState;

  // ValidationSummary(true) に表示するために追加
  var newDictionary = new ModelStateDictionary();
  newDictionary.AddModelError("",
    "ValidationSummary に表示するために追加。");
  ModelState.Merge(newDictionary);

  // エラーメッセージを書き換えることはできる。
  // 「プログラミング ASP.NET MVC」の p186「エラーメッセージ
  // を制御する」参照。同じ Key でマージした方に上書きされる
  ModelState state = dictionary["KeiyakuID"];

  if (state.Errors.Count > 0)
  {
    string msg = state.Errors[0].ErrorMessage;
    if (msg.StartsWith("値"))
    {
      // マージすると Value が null になるので書き戻すために
      // 取得しておく
      ValueProviderResult value = state.Value;
      var newDictionary2 = new ModelStateDictionary();
      newDictionary2.AddModelError("KeiyakuID",
        "入力不正(デフォルトの「値 'xx' は ID に対して" +
        "無効です。」を書き換え)");
      ModelState.Merge(newDictionary2);

      // Value を書き戻す。そうしないと再描画されたとき元の
      // ユーザー入力が表示されず 0 になってしまう
      ModelState["KeiyakuID"].Value = value;
    }
  }
  return View(model);
}

Tags: , ,

Validation

About this blog

2010年5月にこのブログを立ち上げました。主に ASP.NET Web アプリ関係の記事です。

Calendar

<<  2019年3月  >>
242526272812
3456789
10111213141516
17181920212223
24252627282930
31123456

View posts in large calendar