WebMatrix 2 というか、WebPages 2 ではバリデーション周り非常に使いやすくなっていいですね。下手に Fluent Interface で定義させるよりわかりやすいと思いました。
しかし、標準で使えるバリデータは思ったより多くありません。正規表現使えるので大体のことはできますが、ちょっと複雑なことをしようとすると困りますね。なので、今回はカスタムバリデータを作ってみたいと思います。
とりあえず ASP.NET MVC 3 で独自の検証属性を作成して、クライアントサイド検証を行う - しばやん雑記 でクライアントサイド検証を実装した時のように CERO のバリデータを作ります。
バリデータは IValidator インターフェースを実装したクラスです。じゃあこれを実装すれば何でも作れる!と思ったら、ちょっとインターフェースが難しいです。
public interface IValidator { ModelClientValidationRule ClientValidationRule { get; } ValidationResult Validate(ValidationContext validationContext); }
今まで MVC で開発してきて ModelClientValidationRule と ValidationContext とか見ないですよね。このあたりは綺麗にフレームワークが隠してくれてるので、我々は適当に使っておけばよかったのですが、今回は逃げることが出来ません。
とは言っても、ClientValidationRule プロパティはその名の通りクライアントサイド検証用なので、クライアントサイド検証を使わないのなら null 返しとけば問題ありません。
とりあえず完成したコードをいつも通り載せておきます。
public class CeroValidator : IValidator { public CeroValidator(char rating, string errorMessage = null) { _rating = rating; _errorMessage = errorMessage; } private char _rating; private string _errorMessage; public ModelClientValidationRule ClientValidationRule { get { return null; } } public ValidationResult Validate(ValidationContext validationContext) { // ObjectInstance には HttpContext が入ってるので、キャストして取得 var context = (HttpContextBase)validationContext.ObjectInstance; // メンバー名はフォーム要素名なので、コレクションから値を直接取得 var value = context.Request.Form[validationContext.MemberName]; // バリデータでは null or 空文字列の場合は成功にしないとダメ(required があるので) if (string.IsNullOrEmpty(value)) { return ValidationResult.Success; } var result = false; // 数字の時だけ検証する if (value.IsInt()) { var age = value.AsInt(); switch (_rating) { case 'Z': result = age >= 18; break; case 'D': result = age >= 17; break; case 'C': result = age >= 15; break; case 'B': result = age >= 12; break; case 'A': result = true; break; } } if (result) { // 成功したら ValidationResult.Success を返す return ValidationResult.Success; } // 検証に失敗したらエラーメッセージとメンバー名で初期化した ValidationResult を返す return new ValidationResult(_errorMessage, new[] { validationContext.MemberName }); } }
流れはコードとコメントでわかってください、お願いします。基本的には MVC 向けに検証属性作るのとあまり変わらないですが、入力値が文字列なので気を付けてください。
クライアントサイド検証を使いたい場合には MVC 3 と同じように ModelClientValidationRule を作って返せばいいです。JavaScript 側を忘れないように気を付けてくださいね。
そしてサンプルコードは以下のような感じ。Validator.ほげほげ と指定していた部分を new CeroValidator に変えただけです。
Validation.RequireFields("name"); Validation.Add("age", new CeroValidator('Z', "検証に失敗しました")); if (IsPost) { Validation.Validate(); }
実際に試してみたところ、Z 指定なので 18 才未満の場合にはちゃんとエラーが出ました。入力値が分からないので確認しようがないですね(汗