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

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

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

複数プロパティをまたがった検証を実装する

 より複雑なアプリケーションでは、単一のプロパティを検証するばかりではない。複数のプロパティにまたがって、その関連性も含めた検証を行いたいというケースもあるはずだ。本稿の最後では、こうしたより複雑な検証ルールを実装する方法について解説する。

 以下で例示するのは、

「刊行日(Published列)が2007年以降であるかどうかによって、ISBNコード(Isbn列)の検証フォーマットを切り替える」

という例である。2007年以降の書籍については13けたの新コードのみを認め、2006年以前の書籍については10けたの旧コード、13けたの新コードいずれも入力可能とする*6

*6 ISBNコードの体系は2007年以降、新しいものに改められた。詳しくは、「ISBN - Wikipedia」を参照するとよい。

 それではさっそく、具体的なコードを見ていこう。

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel;
using System.Text.RegularExpressions;

namespace MvcApp.Models
{
  public class Book : IValidatableObject
  {
    ……中略……

    // クラス・レベルの検証ルールを定義
    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
      string pattern = "^[0-9]{3}-[0-9]{1}-[0-9]{3,5}-[0-9]{3,5}-[0-9X]{1}$";

      // Published列が2007年以前の場合は正規表現を置き換え
      if (Published.Year < 2007)
      {
        pattern = "^([0-9]{3}-)?[0-9]{1}-[0-9]{3,5}-[0-9]{3,5}-[0-9X]{1}$";
      }

      // 用意された正規表現パターンで入力値をチェック
      var rx = new Regex(pattern);
      if (!rx.IsMatch(Isbn))
      {
        yield return new ValidationResult(
          "ISBNコードの形式が間違っています。", new [] { "Isbn" });
      }
    }

  }
}
Imports System.ComponentModel.DataAnnotations
Imports System.ComponentModel
Imports System.Text.RegularExpressions

Public Class Book : Implements IValidatableObject

  ……中略……

  ' クラス・レベルの検証ルールを定義
  Public Function Validate(validationContext As ValidationContext) As IEnumerable(Of ValidationResult) Implements IValidatableObject.Validate

    Dim list = New List(Of ValidationResult)()
    Dim pattern As String = "^[0-9]{3}-[0-9]{1}-[0-9]{3,5}-[0-9]{3,5}-[0-9X]{1}$"

    ' Published列が2007年以前の場合は、正規表現を置き換え
    If (Published.Year < 2007) Then
      pattern = "^([0-9]{3}-)?[0-9]{1}-[0-9]{3,5}-[0-9]{3,5}-[0-9X]{1}$"
    End If

    ' 用意された正規表現パターンで入力値をチェック
    Dim rx = New Regex(pattern)
    If Not rx.IsMatch(Isbn) Then
        list.Add(New ValidationResult(
            "ISBNコードの形式が間違っています。", New String() {"Isbn"}))
    End If
    Return list
  End Function

End Class
リスト10 複数のプロパティをまたがる検証ルールを実装したコード(上:Book.cs、下:Book.vb)

 複数のプロパティにまたがった検証ルールを実装するには、エンティティに対してIValidatableObjectインターフェイスのValidateメソッドを実装すればよい( )。

 ASP.NET MVC 3では、IValidatableObjectインターフェイスを実装したエンティティをSaveChangesメソッドで保存しようとしたとき、自動的にValidateメソッドを呼び出すので、新たな検証ルールの追加によって、アクション・メソッドやビュー・スクリプトが影響を受けることはない(これまでのコードのみで自動的に検証が実施される)。

 Validateメソッドの中ではまず、DateTime型のPublishedプロパティが2006年以前であるかによって、検証のための正規表現フォーマット(変数pattern)を切り替えている( 、正規表現に関する詳細は、別稿「スマートな文字列処理のための正規表現入門」を参照されたい)。そのうえで、メソッド後半では、与えられた正規表現パターンでIsbn列への入力値が正規表現に合致しているかどうかをチェックしているわけだ。

 検証結果(エラー情報)は、ValidationResultオブジェクト(正確にはIEnumerable<ValidationResult>オブジェクト)として返す必要がある。ValidationResultコンストラクタの構文は、以下のとおり。

ValidationResult(string error, IEnumerable<string> members)
ValidationResultコンストラクタの構文
error:エラー・メッセージ。
members:エラーを関連付けるプロパティ名。

 引数membersは、ビュー・スクリプトにエラーを反映させる際に利用される情報だ。例えばリスト10の例であれば、引数membersにisbnが指定されているので、エラー・メッセージもIsbn列の脇(正確にはIsbn列に関連付いたValidationMessageForメソッド)に表示されることになる。

 以上を理解したら、サンプルを実行し、

  • 刊行日2007年以降の書籍で、10けたのISBNコードが入力できないこと
  • 刊行日2006年以前の書籍で、10けたのISBNコードが許可されていること

をそれぞれ確認してみよう*7

*7 本サンプルを実行するには、前回Isbn列に対して適用しておいたRegularExpression検証をコメントアウトしておく必要がある。


図2 2007年以降の書籍で10けたのISBNコードを入力するとエラー

 以上、今回はアノテーション検証についてさらに踏み込んで、自作の検証ルールを定義する方法について解説した。検証処理の世界はなかなかに奥深いものであるが、まずはここまでを理解しておけば、おおよそのケースはカバーできるはずだ。

 さて、今回でモデルの話題はいったん一区切りとなる。次回は、ビューに目線を転じて、ビュー・スクリプト開発の効率化には欠かせないEditFor/DisplayForメソッドについて解説する予定である。End of Article

 

 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 記事ランキング

本日 月間