다음을 통해 공유


방법: 사용자 지정 특성을 사용하여 데이터 모델의 데이터 필드 유효성 검사 사용자 지정

업데이트: 2008년 7월

ASP.NET Dynamic Data를 사용하면 데이터 계층 수준에서 데이터 필드 유효성 검사를 사용자 지정하고 확장할 수 있습니다. 이 항목에서는 다음 작업을 수행하여 데이터 모델에 데이터 필드 유효성 검사를 추가하는 방법을 설명합니다.

  • 사용자 지정 유효성 검사 특성 만들기. 이 특성을 사용하면 데이터 모델에서 유효성 검사에 사용할 사용자 지정 메타데이터를 만들 수 있습니다.

  • 사용자 지정 유효성 검사 특성 적용. 사용자 지정 특성을 만든 후에는 유효성을 검사할 데이터 필드에 적용합니다.

이 기능의 온라인 예제를 실행해 보십시오.

사용자 지정 유효성 검사 특성 만들기

사용자 지정 유효성 특성을 사용하면 데이터 모델에서 데이터 필드의 유효성을 검사하는 데 사용할 수 있는 메타데이터를 만들 수 있습니다. 이 사용자 지정 특성은 ValidationAttribute 기본 클래스에서 파생시켜야 합니다.

사용자 지정 유효성 검사 특성을 만들려면

  1. 솔루션 탐색기에서 App_Code 폴더를 마우스 오른쪽 단추로 클릭한 다음 새 항목 추가를 클릭합니다.

  2. 새 항목 추가에서 클래스를 클릭합니다.

    이름 상자에 사용자 지정 유효성 검사 특성 클래스의 이름을 입력합니다. 이 이름에는 아직 사용되지 않은 모든 이름을 지정할 수 있습니다. 예를 들어 이름이 CustomAttribute인 사용자 지정 특성 클래스를 만들려면 Visual C#에서는 CustomAttribute.cs를 입력하고, Visual Basic에서는 CustomAttribute.vb를 입력합니다.

  3. 다음 예제에서처럼 Visual Basic의 Imports 키워드 또는 Visual C#의 using 키워드를 사용하여 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
    
  4. 클래스 정의를 다음과 같이 수정합니다.

    • 클래스를 상속할 수 없게 만듭니다. Visual Basic에서는 NotInheritable 키워드를 추가하고 Visual C#에서는 sealed 키워드를 추가합니다.

    • ValidationAttribute 기본 형식에서 클래스를 파생시킵니다.

    • 클래스 정의에 AttributeUsageAttribute 특성을 적용하여 사용자 지정 유효성 검사 특성의 사용 방법을 지정합니다.

    다음 예제에서는 클래스 정의를 보여 줍니다. AttributeUsageAttribute 매개 변수는 사용자 지정 유효성 검사 특성이 속성이나 필드에 한 번만 적용될 수 있도록 설정되었습니다.

    [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
    
  5. 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
    
  6. 필요한 경우 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
    
  7. 클래스 특성 파일을 저장하고 닫습니다.

사용자 지정 유효성 검사 특성 적용

데이터 필드의 유효성 검사를 사용자 지정하려면 데이터 모델을 확장하는 partial 클래스를 구현해야 합니다. 이렇게 하면 데이터 필드에 사용자 지정 특성을 적용할 수 있습니다.

유효성 검사를 위한 partial 클래스를 만들려면

  1. 솔루션 탐색기에서 App_Code 폴더를 마우스 오른쪽 단추로 클릭한 다음 새 항목 추가를 클릭합니다.

  2. Visual Studio에 설치되어 있는 템플릿에서 클래스를 클릭합니다.

    이름 상자에 유효성 검사를 추가할 데이터베이스 테이블의 이름을 입력합니다.

    클래스 이름은 테이블을 나타내는 엔터티 클래스 이름과 일치해야 합니다. 예를 들어 Customers 테이블에 대한 유효성 검사를 추가하려면 파일 이름을 Customer.cs(Visual C#의 경우) 또는 Customer.vb(Visual Basic의 경우)로 지정하고 클래스 이름을 Customer로 지정해야 합니다.

  3. 클래스 정의를 partial 클래스로 만들려면 해당 클래스 정의에 Visual Basic의 Partial 키워드 또는 Visual C#의 partial 키워드를 추가합니다.

  4. Visual C#에 클래스를 만드는 경우 기본 생성자를 삭제합니다.

    다음 예제에서는 업데이트된 클래스 선언을 보여 줍니다.

    public partial class Customer {
    
    }
    
    Partial Public Class Customer
    
    End Class
    
  5. 다음 예제에서처럼 Visual Basic의 Imports 키워드 또는 Visual C#의 using 키워드를 사용하여 System.Web.DynamicDataSystem.ComponentModel.DataAnnotations 네임스페이스에 대한 참조를 추가합니다.

    using System.Web.DynamicData;
    using System.ComponentModel.DataAnnotations;
    
    Imports System.Web.DynamicData
    Imports System.ComponentModel.DataAnnotations
    
  6. 연결된 메타데이터 클래스로 사용할 두 번째 클래스를 같은 파일에 만듭니다. 이 클래스에는 이전에 사용하지 않은 모든 올바른 클래스 이름을 사용할 수 있습니다.

    다음 예제에서는 메타데이터 클래스 선언을 보여 줍니다.

    public class CustomerMetadata
    {
    
    }
    
    Public Class CustomerMetadata 
    
    End Class
    

    연결된 메타데이터 클래스는 유효성 검사 특성을 적용할 수 있는 개체를 제공합니다.

  7. MetadataTypeAttribute 특성을 partial 클래스 정의에 적용합니다. 특성의 매개 변수에 대해서는 이전 단계에서 만든 연결된 메타데이터 클래스의 이름을 사용합니다.

    다음 예제에서는 특성이 추가된 partial 클래스 정의를 보여 줍니다.

    [MetadataType(typeof(CustomerMetadata))]
    public partial class Customer {
    
    }
    
    <MetadataType(GetType(CustomerMetadata))> _
    Partial Public Class Customer
    
    End Class
    

이제 데이터 필드에 사용자 지정 유효성 검사 특성을 적용할 수 있습니다.

데이터 필드에 사용자 지정 유효성 검사 특성을 적용하려면

  1. 메타데이터 클래스에서 유효성을 검사할 데이터 필드와 이름이 일치하는 속성 또는 필드를 만듭니다.

  2. 앞서 만든 사용자 지정 유효성 검사 특성을 유효성을 검사하려는 데이터 필드에 적용합니다.

    다음 예제에서는 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
    
  3. 클래스 파일을 저장하고 닫습니다.

예제

다음 예제에서는 이름이 PhoneMaskAttribute인 사용자 지정 특성을 만들어 AdventureWorksLT 데이터베이스에 있는 Customer 테이블의 Phone 데이터 필드에 적용하는 방법을 보여 줍니다. 이 예제에서는 데이터 모델로 LINQ-to-SQL 클래스를 사용합니다.

이 특성은 Dynamic Data에 특정 전화 번호 형식을 나타내는 마스크와 비교하여 Phone 데이터 필드의 유효성을 검사하도록 지시합니다. 사용자가 입력한 전화 번호가 마스크와 일치하지 않으면 특성 코드에서 사용자 지정 오류를 표시합니다.

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" >
    <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" 
        AutoLoadForeignKeys="true" />


    <form id="form1" >

        <!-- Capture validation exceptions -->
        <asp:DynamicValidator ID="ValidatorID" ControlToValidate="GridView1" 
             /> 

        <asp:GridView ID="GridView1" 
             
            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"   
        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" >
    <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" 
        AutoLoadForeignKeys="true" />


    <form id="form1" >

        <!-- Capture validation exceptions -->
        <asp:DynamicValidator ID="ValidatorID" ControlToValidate="GridView1" 
             /> 

        <asp:GridView ID="GridView1" 
             
            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"   
        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 서비스 팩 1 또는 Visual Web Developer 2008 Express Edition 서비스 팩 1

  • AdventureWorksLT 샘플 데이터베이스. SQL Server 샘플 데이터베이스를 다운로드 및 설치하는 방법에 대한 자세한 내용은 CodePlex 사이트의 Microsoft SQL Server Product Samples: Database를 참조하십시오. 실행 중인 SQL Server 버전(Microsoft SQL Server 2005 또는 Microsoft SQL Server 2008)에 맞는 올바른 샘플 데이터베이스 버전을 설치해야 합니다.

  • Dynamic Data 구동 웹 사이트. 이를 통해 데이터베이스의 데이터 컨텍스트를 만드는 것은 물론 사용자 지정할 데이터 필드와 재정의할 메서드가 들어 있는 클래스를 만들 수 있습니다. 자세한 내용은 Walkthrough: Creating a New Dynamic Data Web Site using Scaffolding를 참조하십시오.

참고 항목

개념

ASP.NET Dynamic Data 필드 템플릿 개요

ASP.NET Dynamic Data 모델 개요

ASP.NET Dynamic Data 개요

참조

ValidationAttribute

DynamicValidator

Partial 클래스 및 메서드(C# 프로그래밍 가이드)

변경 기록

날짜

변경 내용

이유

2008년 7월

항목이 추가되었습니다.

SP1 기능 변경