更新 : 2008 年 7 月
ASP.NET Dynamic Data を使用すると、データ層レベルでデータ フィールドの検証をカスタマイズおよび拡張することができます。このトピックでは、次の操作を行うことで、データ モデルのデータ フィールドの検証を追加する方法について説明します。
カスタム検証属性を作成する。この属性により、データ モデルで検証のために使用するカスタム メタデータを作成できます。
カスタム検証属性を適用する。カスタム属性を作成した後で、検証するデータ フィールドに適用します。
この機能のオンライン サンプルを実行してください。
カスタム検証属性の作成
カスタム検証属性を使用すると、データ モデルでデータ フィールドの検証に使用できるメタデータを作成できます。カスタム属性は、ValidationAttribute 基本クラスから派生させる必要があります。
カスタム検証属性を作成するには
ソリューション エクスプローラで、App_Code フォルダを右クリックし、[新しい項目の追加] をクリックします。
[新しい項目の追加] で [クラス] をクリックします。
[名前] ボックスに、カスタム検証属性クラスの名前を入力します。使用されていない任意の名前を使用できます。たとえば、CustomAttribute という名前のカスタム属性クラスを作成するためには、「CustomAttribute.cs」(Visual C# の場合) または「CustomAttribute.vb」(Visual Basic の場合) という名前を入力します。
Imports キーワード (Visual Basic の場合) または using キーワード (Visual C# の場合) を使用して、System、System.Web.Globalization、および System.ComponentModel.DataAnnotations の各名前空間への参照を追加します。次に例を示します。
using System; using System.Globalization; using System.ComponentModel.DataAnnotations;
Imports System Imports System.Globalization Imports System.ComponentModel.DataAnnotations
クラス定義を次のように変更します。
クラスを継承不可にします。NotInheritable キーワード (Visual Basic の場合) または sealed キーワード (Visual C# の場合) を追加します。
クラスを ValidationAttribute 基本データ型から派生させます。
AttributeUsageAttribute 属性をクラス定義に適用し、カスタム検証属性の使用方法を指定します。
クラス定義の例を次に示します。AttributeUsageAttribute パラメータを設定して、カスタム検証属性がプロパティまたはフィールドに 1 回のみ適用されるようにしています。
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)] sealed public class CustomAttribute : ValidationAttribute { }
<AttributeUsage(AttributeTargets.[Property] Or _ AttributeTargets.Field, AllowMultiple := False)> _ Public NotInheritable Class CustomAttribute Inherits ValidationAttribute .... End Class
IsValid メソッドをオーバーライドし、検証を実行するロジックを追加します。カスタム検証に成功した場合は true が返され、失敗した場合は false が返されます。検証対象の値は、唯一のパラメータとしてメソッドに渡されます。
このメソッドのオーバーライドされたコードは次のようになります。
public override bool IsValid(object value) { bool result = true; // Add validation logic here. return result; }
Public Overrides Function IsValid( _ ByVal value As Object) As Boolean ' Add validation logic here. Return result End Function
必要に応じて、FormatErrorMessage メソッドをオーバーライドしてカスタム エラー メッセージの書式設定を実行します。
次の例は、検証に失敗したデータ フィールドの名前を使用してカスタム エラー メッセージを作成する方法を示しています。カスタム属性がデータ フィールドに適用されると、ErrorMessageString 値がパラメータとして渡されます。
public override string FormatErrorMessage(string name) { return String.Format(CultureInfo.CurrentCulture, ErrorMessageString, name); }
Public Overrides Function FormatErrorMessage( _ ByVal name As String) As String Return [String].Format(CultureInfo.CurrentCulture, _ ErrorMessageString, name) End Function
クラス属性ファイルを保存して閉じます。
カスタム検証属性の適用
データ フィールドの検証をカスタマイズするには、データ モデルを拡張する部分クラスを実装する必要があります。これにより、カスタム属性をデータ フィールドに適用できます。
検証用の部分クラスを作成するには
ソリューション エクスプローラで、App_Code フォルダを右クリックし、[新しい項目の追加] をクリックします。
[Visual Studio にインストールされたテンプレート] の [クラス] をクリックします。
[名前] ボックスに、検証を追加するデータベース テーブルの名前を入力します。
クラス名は、テーブルを表すエンティティ クラス名と一致させる必要があります。たとえば、Customers テーブルに検証を追加する場合は、ファイルに「Customer.cs」(Visual C# の場合) または「Customer.vb」(Visual Basic の場合) という名前を付け、クラス名を「Customer」にする必要があります。
クラス定義に Partial キーワード (Visual Basic の場合) または partial キーワード (Visual C# の場合) を追加して部分クラスにします。
Visual C# でクラスを作成する場合は、既定のコンストラクタを削除します。
更新後のクラス宣言を次の例に示します。
public partial class Customer { }
Partial Public Class Customer End Class
Imports キーワード (Visual Basic の場合) または using キーワード (Visual C# の場合) を使用して、System.Web.DynamicData 名前空間と System.ComponentModel.DataAnnotations 名前空間への参照を追加します。次に例を示します。
using System.Web.DynamicData; using System.ComponentModel.DataAnnotations;
Imports System.Web.DynamicData Imports System.ComponentModel.DataAnnotations
同じファイル内に、関連メタデータ クラスとして機能するクラスを追加します。このクラスには、クラス名として有効であり、まだ使用されていない名前であれば、任意の名前を付けることができます。
メタデータのクラス宣言を次の例に示します。
public class CustomerMetadata { }
Public Class CustomerMetadata End Class
関連メタデータ クラスは、検証属性の適用先となるオブジェクトを提供します。
部分クラス定義に MetadataTypeAttribute 属性を適用します。属性のパラメータには、前の手順で作成した関連メタデータ クラスの名前を使用します。
属性が適用された部分クラス定義を次の例に示します。
[MetadataType(typeof(CustomerMetadata))] public partial class Customer { }
<MetadataType(GetType(CustomerMetadata))> _ Partial Public Class Customer End Class
これで、カスタム検証属性をデータ フィールドに適用できます。
カスタム検証属性をデータ フィールドに適用するには
メタデータ クラスに、検証するデータ フィールドに対応のプロパティ (フィールド) を作成します。
前に作成したカスタム検証属性を、検証するデータ フィールドに適用します。
次の例は、カスタム検証属性を Phone データ フィールドに適用する方法を示しています。
public partial class CustomerMetadata { [CustomAttribute(parm1, ErrorMessage = "{0} field validation failed.")] public object Phone; }
Public Class CustomerMetadata <PhoneMask(parm1, _ ErrorMessage:="{0} field validation failed.")> _ Public Phone As Object End Class
クラス ファイルを保存して閉じます。
使用例
次の例は、PhoneMaskAttribute という名前のカスタム属性を作成して、AdventureWorksLT データベースの Customer テーブルの Phone データ フィールドに適用する方法を示しています。この例では、データ モデルに LINQ-to-SQL クラスを使用します。
属性により、特定の電話番号形式を表すマスクに対して Phone データ フィールドを検証するように Dynamic Data に指示しています。ユーザーの入力した電話番号がマスクに一致しない場合は、属性のコードからカスタム エラーが発行されます。
Imports Microsoft.VisualBasic
Imports System
Imports System.Globalization
Imports System.ComponentModel.DataAnnotations
<AttributeUsage(AttributeTargets.[Property] Or AttributeTargets.Field, AllowMultiple:=False)> _
Public NotInheritable Class PhoneMaskAttribute
Inherits ValidationAttribute
' Internal field to hold the mask value.
ReadOnly _mask As String
Public ReadOnly Property Mask() As String
Get
Return _mask
End Get
End Property
Public Sub New(ByVal mask As String)
_mask = mask
End Sub
Public Overrides Function IsValid( _
ByVal value As Object) As Boolean
Dim phoneNumber As String = DirectCast(value, String)
Dim result As Boolean = True
If Me.Mask <> Nothing Then
result = MatchesMask(Me.Mask, phoneNumber)
End If
Return result
End Function
' Checks if the entered phone number matches the mask.
Public Shared Function MatchesMask(ByVal mask As String, _
ByVal phoneNumber As String) As Boolean
If mask.Length <> phoneNumber.Trim().Length Then
' Length mismatch.
Return False
End If
Dim i As Integer = 0
While i < mask.Length
If mask(i) = "d"c _
AndAlso Char.IsDigit(phoneNumber(i)) = False Then
' Digit expected at this position.
Return False
End If
If mask(i) = "-"c AndAlso phoneNumber(i) <> "-"c Then
' Spacing character expected at this position.
Return False
End If
System.Math.Max(System.Threading.Interlocked.Increment(i), i - 1)
End While
Return True
End Function
Public Overrides Function FormatErrorMessage( _
ByVal name As String) As String
Return [String].Format(CultureInfo.CurrentCulture, _
ErrorMessageString, name, Me.Mask)
End Function
End Class
using System;
using System.Globalization;
using System.ComponentModel.DataAnnotations;
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
sealed public class PhoneMaskAttribute : ValidationAttribute
{
// Internal field to hold the mask value.
readonly string _mask;
public string Mask
{
get { return _mask; }
}
public PhoneMaskAttribute(string mask)
{
_mask = mask;
}
public override bool IsValid(object value)
{
var phoneNumber = (String)value;
bool result = true;
if (this.Mask != null)
{
result = MatchesMask(this.Mask, phoneNumber);
}
return result;
}
// Checks if the entered phone number matches the mask.
internal bool MatchesMask(string mask, string phoneNumber)
{
if (mask.Length != phoneNumber.Trim().Length)
{
// Length mismatch.
return false;
}
for (int i = 0; i < mask.Length; i++)
{
if (mask[i] == 'd' && char.IsDigit(phoneNumber[i]) == false)
{
// Digit expected at this position.
return false;
}
if (mask[i] == '-' && phoneNumber[i] != '-')
{
// Spacing character expected at this position.
return false;
}
}
return true;
}
public override string FormatErrorMessage(string name)
{
return String.Format(CultureInfo.CurrentCulture,
ErrorMessageString, name, this.Mask);
}
}
Imports Microsoft.VisualBasic
Imports System.Web.DynamicData
Imports System.ComponentModel.DataAnnotations
<MetadataType(GetType(CustomerMetadata))> _
Partial Public Class Customer
End Class
Public Class CustomerMetadata
<PhoneMask("999-999-9999", _
ErrorMessage:="{0} field value does not match the mask {1}.")> _
Public Phone As Object
End Class
using System.Web.DynamicData;
using System.ComponentModel.DataAnnotations;
[MetadataType(typeof(CustomerMetadata))]
public partial class Customer
{
}
public class CustomerMetadata
{
[PhoneMask("999-999-9999",
ErrorMessage = "{0} value does not match the mask {1}.")]
public object Phone;
}
<%@ Page Language="VB"
AutoEventWireup="true" CodeFile="CustomAttributeValidation.aspx.vb"
Inherits="CustomAttributeValidation" %>
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<title></title>
<link href="~/Site.css" rel="stylesheet" type="text/css" />
</head>
<body>
<h2>Example: <%=Title%></h2>
<!-- Enable dynamic behavior. The GridView must be
registered with the manager. See code-behind file. -->
<asp:DynamicDataManager ID="DynamicDataManager1" runat="server"
AutoLoadForeignKeys="true" />
<form id="form1" runat="server">
<!-- Capture validation exceptions -->
<asp:DynamicValidator ID="ValidatorID" ControlToValidate="GridView1"
runat="server" />
<asp:GridView ID="GridView1"
runat="server"
DataSourceID="GridDataSource"
AutoGenerateColumns="false"
AutoGenerateEditButton="true"
AllowPaging="true"
PageSize="10"
AllowSorting="true">
<Columns>
<asp:DynamicField DataField="FirstName" />
<asp:DynamicField DataField="LastName" />
<asp:DynamicField DataField="Phone" />
</Columns>
</asp:GridView>
</form>
<!-- Connect to the database -->
<asp:LinqDataSource ID="GridDataSource" runat="server"
TableName="Customers" EnableUpdate="true"
ContextTypeName="AdventureWorksLTDataContext">
</asp:LinqDataSource>
</body>
</html>
<%@ Page Language="C#"
AutoEventWireup="true" CodeFile="CustomAttributeValidation.aspx.cs"
Inherits="CustomAttributeValidation" %>
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<title></title>
<link href="~/Site.css" rel="stylesheet" type="text/css" />
</head>
<body>
<h2>Example: <%=Title%></h2>
<!-- Enable dynamic behavior. The GridView must be
registered with the manager. See code-behind file. -->
<asp:DynamicDataManager ID="DynamicDataManager1" runat="server"
AutoLoadForeignKeys="true" />
<form id="form1" runat="server">
<!-- Capture validation exceptions -->
<asp:DynamicValidator ID="ValidatorID" ControlToValidate="GridView1"
runat="server" />
<asp:GridView ID="GridView1"
runat="server"
DataSourceID="GridDataSource"
AutoGenerateColumns="false"
AutoGenerateEditButton="true"
AllowPaging="true"
PageSize="10"
AllowSorting="true">
<Columns>
<asp:DynamicField DataField="FirstName" />
<asp:DynamicField DataField="LastName" />
<asp:DynamicField DataField="Phone" />
</Columns>
</asp:GridView>
</form>
<!-- Connect to the database -->
<asp:LinqDataSource ID="GridDataSource" runat="server"
TableName="Customers" EnableUpdate="true"
ContextTypeName="AdventureWorksLTDataContext">
</asp:LinqDataSource>
</body>
</html>
Imports System
Imports System.Collections
Imports System.Configuration
Imports System.Web.DynamicData
Partial Public Class CustomAttributeValidation
Inherits System.Web.UI.Page
Protected _table As MetaTable
Protected Sub Page_Init(ByVal sender As Object, ByVal e As EventArgs)
' Register control with the data manager.
DynamicDataManager1.RegisterControl(GridView1)
End Sub
Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs)
' Get the table entity.
_table = GridDataSource.GetTable()
' Assign title dynamically.
Title = String.Concat( _
"Customize <i>Phone</i> Data Field Validation", _
"Using a Custom Attribute")
End Sub
End Class
using System;
using System.Collections;
using System.Configuration;
using System.Web.DynamicData;
public partial class CustomAttributeValidation : System.Web.UI.Page
{
protected MetaTable _table;
protected void Page_Init(object sender, EventArgs e)
{
// Register control with the data manager.
DynamicDataManager1.RegisterControl(GridView1);
}
protected void Page_Load(object sender, EventArgs e)
{
// Get the table entity.
_table = GridDataSource.GetTable();
// Assign title dynamically.
Title = string.Concat("Customize <i>Phone</i> Data Field Validation",
"Using a Custom Attribute");
}
}
コードのコンパイル方法
このコード例をコンパイルするには、以下が必要です。
Microsoft Visual Studio 2008 Service Pack 1 または Visual Web Developer 2008 Express Edition Service Pack 1。
AdventureWorksLT サンプル データベース。SQL Server のサンプル データベースをダウンロードしてインストールする方法については、CodePlex サイトの「Microsoft SQL Server Product Samples: Database」を参照してください。実行している SQL Server のバージョン (Microsoft SQL Server 2005 または Microsoft SQL Server 2008) に対応した正しいバージョンのサンプル データベースをインストールしてください。
動的なデータ ドリブン Web サイトの作成。これにより、データベースのデータ コンテキストと、カスタマイズするデータ フィールドおよびオーバーライドするメソッドを持つクラスを作成できます。詳細については、「Walkthrough: Creating a New Dynamic Data Web Site using Scaffolding」を参照してください。
参照
概念
ASP.NET Dynamic Data のフィールド テンプレートの概要
参照
履歴の変更
日付 |
履歴 |
理由 |
---|---|---|
2008 年 7 月 |
トピックを追加 |
SP1 機能変更 |