xVal バージョン1.0 がリリースされました。
xVal
http://xval.codeplex.com/
xVal v1.0 Now Available
http://blog.codeville.net/2009/09/17/xval-v10-now-available/
ASP.NET MVC でバリデーションを行うとき、同じ定義をサーバーサイドとクライアントサイドの両方記述する必要がありましたが、xVal を使うと1カ所にまとめられます。
demo project を参考にしながら、ASP.NET MVC でサーバーサイドを DataAnnotations 、クライアントサイドに jQuery Validation を使って簡単に試してみます。
ASP.NET MVC プロジェクトでデフォルトで作成される Home の Index.aspx に 入力フォームを設置し、エラーがなければ Aboutにリダイレクトする手抜きな実装です。
環境:Windows 7, .NET Framework 3.5, ASP.NET MVC 1.0, xVal 1.0
1.ファイルのダウンロード
xVal と jQuery Validation をダウンロードします。
2.ASP.NET MVC プロジェクトを作成し、xVal.jquery.validate.js と jquery.validate.js を Scripts フォルダにコピーし、xVal.dll と System.ComponentModel.DataAnnotations を参照に追加します。
3.今回使用する Module, View, Controllerを作成又は修正します。
Module : Person クラスを作成します。
using System.Linq;
using System.ComponentModel.DataAnnotations;
using xVal.ServerSide;
using xValTest.Helpers;
namespace xValTest.Models
{
public class Person
{
[Required(ErrorMessage = "名前を入力してください。")]
[StringLength(50, ErrorMessage = "名前が50文字を超えています。長すぎませんか?")]
public string Name { get; set; }
[Required(ErrorMessage = "年齢を入力してください。")]
[Range(0, 100, ErrorMessage = "100歳までしか対応してません。")]
public int? Age { get; set; }
public void Validation()
{
var errors = DataAnnotationsValidationRunner.GetErrors(this).ToList();
if (errors.Any())
throw new RulesException(errors);
}
}
}
View : Home/Index.aspx に入力フォーム用のタグを追加します。
<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage" %>
<asp:Content ID="indexTitle" ContentPlaceHolderID="TitleContent" runat="server">
Home Page
</asp:Content>
<asp:Content ID="indexContent" ContentPlaceHolderID="MainContent" runat="server">
<h2><%= Html.Encode(ViewData["Message"]) %></h2>
<p>
To learn more about ASP.NET MVC visit <a href="http://asp.net/mvc" title="ASP.NET MVC Website">http://asp.net/mvc</a>.
</p>
<div>
<% using (Html.BeginForm()) { %>
<p><label for="person.Name">名前</label></p>
<p><% =Html.TextBox("person.Name")%> </p>
<br />
<p><label for="person.Age">年齢</label></p>
<p><% =Html.TextBox("person.Age")%> </p>
<input type="submit" value="送信" />
<% } %>
</div>
</asp:Content>
Controller : HomeController.cs を修正します。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using xValTest.Models;
using xVal.ServerSide;
namespace xValTest.Controllers
{
[HandleError]
public class HomeController : Controller
{
public ActionResult Index()
{
ViewData["Message"] = "Welcome to ASP.NET MVC!";
return View();
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Index(Person person)
{
ViewData["Message"] = "Welcome to ASP.NET MVC!";
try
{
person.Validation();
return RedirectToAction("About");
}
catch (RulesException ex)
{
ex.AddModelStateErrors(ModelState, "person");
return View();
}
}
public ActionResult About()
{
return View();
}
}
}
4.Helpersフォルダを作成し、DataAnnotationsValidationRunner クラスを作成します。※コードは demo project と同じです。
DataAnnotationsValidationRunner.cs
using System.Collections.Generic;
using System.Linq;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using xVal.ServerSide;
namespace xValTest.Helpers
{
public static class DataAnnotationsValidationRunner
{
public static IEnumerable GetErrors(object instance)
{
var metadataAttrib = instance.GetType().GetCustomAttributes(typeof(MetadataTypeAttribute), true).OfType().FirstOrDefault();
var buddyClassOrModelClass = metadataAttrib != null ? metadataAttrib.MetadataClassType : instance.GetType();
var buddyClassProperties = TypeDescriptor.GetProperties(buddyClassOrModelClass).Cast();
var modelClassProperties = TypeDescriptor.GetProperties(instance.GetType()).Cast();
return from buddyProp in buddyClassProperties
join modelProp in modelClassProperties on buddyProp.Name equals modelProp.Name
from attribute in buddyProp.Attributes.OfType()
where !attribute.IsValid(modelProp.GetValue(instance))
select new ErrorInfo(buddyProp.Name, attribute.FormatErrorMessage(string.Empty), instance);
}
}
}
ここまででサーバーサイドの実装は完了です。続いてクライアントサイドのバリデーションを実装します。 まずは、クライアントサイドの処理で使用するJavaScriptのライブラリを読み込むため、MVC View Master ページのheadに追加します。
Views/Shared/Site.Master
<head runat="server">
<title><asp:ContentPlaceHolder ID="TitleContent" runat="server" /></title>
<link href="../../Content/Site.css" rel="stylesheet" type="text/css" />
<script type="text/javascript" src="<%= ResolveUrl("~/Scripts/jquery-1.3.2.js")%>"></script>
<script type="text/javascript" src="<%= ResolveUrl("~/Scripts/jquery.validate.js")%>"></script>
<script type="text/javascript" src="<%= ResolveUrl("~/Scripts/xVal.jquery.validate.js")%>"></script>
</head>
先ほどフォームを追加した Index.aspx に今度はクライアントサイドでバリデーションを行うため、ネームスペースの追加、エラーメッセージを表示するコード、JavaScript出力コードを追加し、下記のように修正します。
<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage" %>
<%@ Import Namespace="xVal.Html"%>
<%@ Import Namespace="xValTest.Models"%>
<asp:Content ID="indexTitle" ContentPlaceHolderID="TitleContent" runat="server">
Home Page
</asp:Content>
<asp:Content ID="indexContent" ContentPlaceHolderID="MainContent" runat="server">
<h2><%= Html.Encode(ViewData["Message"]) %></h2>
<p>
To learn more about ASP.NET MVC visit <a href="http://asp.net/mvc" title="ASP.NET MVC Website">http://asp.net/mvc</a>.
</p>
<div>
<% using (Html.BeginForm()) { %>
<p><label for="person.Name">名前</label></p>
<p><% =Html.TextBox("person.Name")%> </p>
<br />
<p><label for="person.Age">年齢</label></p>
<p><% =Html.TextBox("person.Age")%> </p>
<input type="submit" value="送信" />
<% } %>
</div>
<div id="validationSummary">
<%= Html.ValidationSummary() %>
</div>
<%= Html.ClientSideValidation("person", typeof(Person))
.UseValidationSummary("validationSummary") %>
</asp:Content>
これだけで完成です。キャプチャーでは動きがわからないですが、こんな感じになります。同じ定義を書かなくて良いので楽になりますね。
