連載:ASP.NET MVC入門【バージョン3対応】

第4回 検証属性の自作とクラス・レベルのモデル検証

山田 祥寛(http://www.wings.msn.to/
2011/06/17
Page1 Page2 Page3

自作の検証属性を定義する(クライアントサイド編)

 以上でInArray検証はそれなりに動作するようになったが、このままでは十分とはいえない。先ほども触れたように、InArray検証はクライアントサイド検証に対応していないため、ほかのクライアントサイド検証がすべてクリアになり、サーバに要求が到達するまで検証が実施されないのだ。

 このままでも最低限は事足りるが、余計なトラフィックを発生させたくないという意味では、一次的な検証手段であるクライアントサイド検証はきちんと実装しておくのが望ましい。

■InArray属性での準備

 クライアントサイド検証を有効にするには、まず検証属性(InArrayAttributeクラス)の側で、検証に必要な情報(パラメータやエラー・メッセージ)をクライアントに引き渡す必要がある。これには、IClientValidatableインターフェイスのGetClientValidationRulesメソッドを実装すればよい。

using System.Web.Mvc;
using System.Collections.Generic;

namespace MvcApp.Models
{
  public class InArrayAttribute : ValidationAttribute, IClientValidatable
  {
    ……中略……

    // クライアントに送信する検証情報の生成
    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
    {
      // 検証ルールを準備
      var rule = new ModelClientValidationRule
      {
        ValidationType = "inarray", // 検証名
        ErrorMessage = FormatErrorMessage(metadata.GetDisplayName()) // エラー
      };
      rule.ValidationParameters["opts"] = _opts; // 検証パラメータ
      yield return rule;
    }

  }
}
<AttributeUsage(AttributeTargets.Property, AllowMultiple:=False)>
Public Class InArrayAttribute : Inherits ValidationAttribute : Implements IClientValidatable

  ……中略……

  ' クライアントに送信する検証情報の生成
  Public Function GetClientValidationRules(ByVal metadata As ModelMetadata, ByVal context As ControllerContext) As IEnumerable(Of ModelClientValidationRule) Implements IClientValidatable.GetClientValidationRules

    ' 検証ルールを準備
    Dim rule = New ModelClientValidationRule() With
    {
      .ValidationType = "inarray", ' 検証名
      .ErrorMessage = FormatErrorMessage(metadata.GetDisplayName()) ' エラー
    }
    rule.ValidationParameters("opts") = _opts ' 検証パラメータ
    Dim list = New List(Of ModelClientValidationRule)()
    list.Add(rule)
    Return list
  End Function


End Class
リスト6 クライアントサイドに検証情報を送信するためのコード(上:InArrayAttribute.cs、下:InArrayAttribute.vb)

 GetClientValidationRulesメソッドは、クライアントサイドに渡すべき検証情報を返すためのメソッドだ。ビュー・スクリプトでは、ここで生成された情報を基に、検証に必要なタグ(属性)を組み立てることになる。

 以下に、検証情報を表すModelClientValidationRuleクラス(System.Web.Mvc名前空間)の主なプロパティをまとめておく。

プロパティ 概要
ErrorMessage 検証エラー・メッセージ
ValidationParameters 検証パラメータ(キー名と値のセット)
ValidationType 検証型を識別する名前
表2 ModelClientValidationRuleクラス(System.Web.Mvc名前空間)の主なプロパティ

 検証の型、検証パラメータの名前には、いずれも小文字だけしか利用できないので注意されたい*4

*4 控えめなJavaScriptで利用しているdata-xxxxx属性(xxxxxはパラメータ名)が大文字の名前を認めていないためだ。控えめなJavaScriptを無効にした場合には、この制限は課されない。

 エラー・メッセージ(ErrorMessageプロパティ)には、先ほど準備しておいたFormatErrorMessageメソッドで整形済みのエラー・メッセージを渡す必要がある。FormatErrorMessageの引数(表示名)は、GetClientValidationRulesメソッドに渡された引数(ModelMetadataオブジェクト)のGetDisplayNameメソッドで取得できる。

 後は、生成したModelClientValidationRuleオブジェクトを、(要求されている戻り値がIEnumerable型なので)yield return文で返せばよいだけだ。

 これでクライアントサイドには、以下のようなコードが出力されるようになる(先ほどと同じく、Publish列にInArray検証が適用されている場合)。確かに、エラー・メッセージや検証パラメータが<input>要素に埋め込まれていることが確認できる。

<input class="text-box single-line" data-val="true" data-val-inarray="出版社は翔泳社,技術評論社,秀和システム,毎日コミュニケーションズ,日経BP社,インプレスジャパンのいずれかで指定してください。" data-val-inarray-opts="翔泳社,技術評論社,秀和システム,毎日コミュニケーションズ,日経BP社,インプレスジャパン" id="Publish" name="Publish" type="text" value="" />
リスト7 リスト6の実装によりクライアントに出力されるコード

■jQuery Validationにinarray検証を追加する

 もっとも、以上で行ったことはあくまで<input>要素に、検証に必要なパラメータ情報を引き渡すまでで、(当然であるが)クライアントサイド検証そのものを実施するわけではない。続いて、クライアントサイド検証を担当するjQuery Validation*5に対して、自作のinarray検証を登録する必要がある。

*5 jQuery ValidationはjQueryのプラグイン。標準の検証属性におけるクライアントサイド検証も、このjQuery Validationの上で行われている。

 以下が、その具体的なコードだ。

// インテリセンス機能を有効化
/// <reference path="jquery-1.4.4-vsdoc.js" />
/// <reference path="jquery.validate-vsdoc.js" />
/// <reference path="jquery.validate.unobtrusive.min.js" />

// inarray検証をjQuery Validationに登録
$.validator.addMethod('inarray',
  function (value, element, param) {

    // 入力値が空の場合は検証をスキップ
    value = $.trim(value);
    if (value === '') {
      return true;
    }

    // カンマ区切りテキストを分解し、入力値valueと比較
    if ($.inArray(value, param.split(',')) === -1){
      return false;
    }
    return true;
  });

// inarray検証と、そのパラメータoptsを登録
$.validator.unobtrusive.adapters.addSingleVal('inarray', 'opts');
リスト8 jQuery Validationにinarray検証を登録するコード(InArray.js)

 ここでポイントとなるのは、以下の3点である。

JavaScriptのIntelliSense(インテリセンス)機能を有効化する

 冒頭のドキュメンテーション・コメント(「///」で始まるコメント)は、.jsファイルでjQuery関連のIntelliSenseを有効にするための記述だ。実行するうえで必須ではないが、コード入力が格段に楽になるのでまずは明記する癖を付けておくのが望ましい。

 なお、JavaScriptコードに対してIntelliSenseを有効にする方法の詳細については、拙稿「ASP.NETアプリ開発者のためのVisual Studio 2008新機能 Part I」でも触れているので、併せて参照していただきたい。

自作の検証ルールを登録する$.validator.addMethodメソッド

 自作の検証ルールをjQuery Validationに登録するのは、$.validator.addMethodメソッドの役割だ。

$.validator.addMethod(name, method)
$.validator.addMethodメソッドの構文
name:検証名
method:検証時に実行されるコールバック関数

 検証の実処理を表すのは、第2引数method(検証コールバック関数)の役割だ。検証コールバック関数のシグニチャは以下のとおり。

function (value, element, param)
検証コールバック関数の構文
value:フォームから渡された値。
element:検証対象の要素。
param:検証パラメータ。

 リスト8の例では、引数paramとして値リスト(サンプルでは、「出版社は翔泳社,技術評論社,秀和システム,毎日コミュニケーションズ,日経BP社,インプレスジャパン」)を受け取ることを想定している。サンプルでは、この値リストをsplitメソッドで分割した結果を、$.inArrayメソッドで走査しているわけだ。これら一連の流れは、InArrayAttribute.IsValidメソッド(リスト1)のそれと同じなので、比較して確認してみるとよいだろう。

検証型と検証パラメータをjQuery Validationに登録する

 これでinarray検証がjQuery Validationに登録されたわけだが、これだけではまだクライアントサイド検証は実行されない。data-val-inarray、data-val-inarray-opts属性によって、inarray検証が呼び出されるという関連付けがまだされていないからだ。

 この関連付けを行っているのが、 のaddSingleValメソッドである。

addSingleVal(name, attr)
addSingleValメソッドの構文
name:検証名
attr:パラメータ名

 リスト8の例であれば、パラメータoptsを持つinarray検証を登録しなさいという意味になる。実は、先ほどの検証コールバック関数の引数paramにoptsパラメータの値が渡されていたのも、addSingleValメソッドによってパラメータの関連付けが行われていたためだ。

 ちなみに、data-xxxxx属性とjQuery Validationとを関連付けるaddXxxxxメソッドには、パラメータの数に応じてaddBool、addMinMax、addなどのメソッドが用意されている。例えば、addBoolメソッドであればパラメータを持たない最もシンプルな検証を登録する(おおよそのケースでは、これとaddSingleValメソッドで賄えるはずだ)。

addBool(name)
addBoolメソッドの構文
name:検証名

 そのほか、addXxxxxメソッドの詳細について知りたい方は、「Unobtrusive Client Validation in ASP.NET MVC 3」も確認しておくとよいだろう。

■クライアント検証の有効化とサンプルの確認

 後は、ビュー・スクリプトに対して作成したInArray.jsをインポートするだけだ。

<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>

<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>

<script src="@Url.Content("~/Scripts/InArray.js")" type="text/javascript"></script>
リスト9 ビュー・スクリプトでInArray.jsをインポート(Create.cshtml/Create.vbhtml)

 以上を理解できたらサンプルを実行し、あえて誤った値を入力してみよう。今度は、通信が発生する前に検証が実施され、エラー・メッセージが表示されることが確認できる。


 INDEX
  ASP.NET MVC入門【バージョン3対応】
  第4回 検証属性の自作とクラス・レベルのモデル検証
    1.自作の検証属性を定義する(サーバサイド編)
  2.自作の検証属性を定義する(クライアントサイド編)
    3.複数プロパティをまたがった検証を実装する
 
インデックス・ページヘ  「ASP.NET MVC入門【バージョン3対応】」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間