IDataErrorInfo 인터페이스를 사용한 유효성 검사(C#)

작성자 : Stephen Walther

Stephen Walther는 모델 클래스에서 IDataErrorInfo 인터페이스를 구현하여 사용자 지정 유효성 검사 오류 메시지를 표시하는 방법을 보여줍니다.

이 자습서의 목표는 ASP.NET MVC 애플리케이션에서 유효성 검사를 수행하는 한 가지 방법을 설명하는 것입니다. 필요한 양식 필드에 대한 값을 제공하지 않고 다른 사용자가 HTML 양식을 제출하지 못하도록 하는 방법을 알아봅니다. 이 자습서에서는 IErrorDataInfo 인터페이스를 사용하여 유효성 검사를 수행하는 방법을 알아봅니다.

가정

이 자습서에서는 MoviesDB 데이터베이스와 Movies 데이터베이스 테이블을 사용합니다. 이 테이블에는 다음 열이 있습니다.

열 이름 데이터 형식 Null 허용
Id Int 거짓
제목 Nvarchar (100) 거짓
감독 Nvarchar (100) 거짓
DateReleased DateTime 거짓

이 자습서에서는 Microsoft Entity Framework를 사용하여 데이터베이스 모델 클래스를 생성합니다. Entity Framework에서 생성된 Movie 클래스가 그림 1에 표시됩니다.

Movie 엔터티

그림 01: 영화 엔터티(전체 크기 이미지를 보려면 클릭)

참고

Entity Framework를 사용하여 데이터베이스 모델 클래스를 생성하는 방법에 대한 자세한 내용은 Entity Framework를 사용하여 모델 클래스 만들기 자습서를 참조하세요.

컨트롤러 클래스

홈 컨트롤러를 사용하여 영화를 나열하고 새 영화를 만듭니다. 이 클래스의 코드는 목록 1에 포함되어 있습니다.

목록 1 - Controllers\HomeController.cs

using System.Linq;
using System.Web.Mvc;
using MvcApplication1.Models;

namespace MvcApplication1.Controllers
{

    public class HomeController : Controller
    {
        private MoviesDBEntities _db = new MoviesDBEntities();

        public ActionResult Index()
        {
            return View(_db.MovieSet.ToList());
        }

        public ActionResult Create()
        {
            return View();
        }

        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult Create([Bind(Exclude = "Id")] Movie movieToCreate)
        {
            // Validate
            if (!ModelState.IsValid)
                return View();

            // Add to database
            try
            {
                _db.AddToMovieSet(movieToCreate);
                _db.SaveChanges();

                return RedirectToAction("Index");
            }
            catch
            {
                return View();
            }
        }

    }
}

목록 1의 홈 컨트롤러 클래스에는 두 개의 Create() 작업이 포함됩니다. 첫 번째 작업은 새 영화를 만들기 위한 HTML 양식을 표시합니다. 두 번째 Create() 작업은 데이터베이스에 새 동영상의 실제 삽입을 수행합니다. 두 번째 Create() 작업은 첫 번째 Create() 작업으로 표시되는 폼이 서버에 제출될 때 호출됩니다.

두 번째 Create() 작업에는 다음 코드 줄이 포함됩니다.

// Validate
if (!ModelState.IsValid)
    return View();

유효성 검사 오류가 있는 경우 IsValid 속성은 false를 반환합니다. 이 경우 영화를 만들기 위한 HTML 양식이 포함된 만들기 보기가 다시 표시됩니다.

Partial 클래스 만들기

Movie 클래스는 Entity Framework에서 생성됩니다. 솔루션 탐색기 창에서 MoviesDBModel.edmx 파일을 확장하고 MoviesDBModel.Designer 열면 Movie 클래스에 대한 코드를 볼 수 있습니다. 코드 편집기에서 cs 파일(그림 2 참조).

Movie 엔터티에 대한 코드

그림 02: Movie 엔터티에 대한 코드(전체 크기 이미지를 보려면 클릭)

Movie 클래스는 부분 클래스입니다. 즉, 동일한 이름의 다른 부분 클래스를 추가하여 Movie 클래스의 기능을 확장할 수 있습니다. 유효성 검사 논리를 새 partial 클래스에 추가합니다.

목록 2의 클래스를 Models 폴더에 추가합니다.

목록 2 - Models\Movie.cs

using System.Collections.Generic;
using System.ComponentModel;

namespace MvcApplication1.Models
{

    public partial class Movie 
    {

    }
}

목록 2의 클래스에는 부분 한정자가 포함되어 있습니다. 이 클래스에 추가하는 모든 메서드 또는 속성은 Entity Framework에서 생성된 Movie 클래스의 일부가 됩니다.

OnChanging 및 OnChanged Partial 메서드 추가

Entity Framework에서 엔터티 클래스를 생성하면 Entity Framework는 부분 메서드를 클래스에 자동으로 추가합니다. Entity Framework는 클래스의 각 속성에 해당하는 OnChanging 및 OnChanged 부분 메서드를 생성합니다.

Movie 클래스의 경우 Entity Framework는 다음 메서드를 만듭니다.

  • OnIdChanging
  • OnIdChanged
  • OnTitleChanging
  • OnTitleChanged
  • OnDirectorChanging
  • OnDirectorChanged
  • OnDateReleasedChanging
  • OnDateReleasedChanged

OnChanging 메서드는 해당 속성이 변경되기 직전에 호출됩니다. OnChanged 메서드는 속성이 변경된 직후에 호출됩니다.

이러한 부분 메서드를 활용하여 Movie 클래스에 유효성 검사 논리를 추가할 수 있습니다. 목록 3의 Movie 클래스 업데이트는 Title 및 Director 속성에 없음 값이 할당되어 있는지 확인합니다.

참고

partial 메서드는 구현할 필요가 없는 클래스에 정의된 메서드입니다. partial 메서드를 구현하지 않으면 컴파일러는 메서드 시그니처와 메서드에 대한 모든 호출을 제거하므로 partial 메서드와 관련된 런타임 비용이 없습니다. Visual Studio Code 편집기에서 키워드(keyword) 부분 뒤에 공백을 입력하여 partial 메서드를 추가하여 구현할 부분 목록을 볼 수 있습니다.

목록 3 - Models\Movie.cs

using System.Collections.Generic;
using System.ComponentModel;

namespace MvcApplication1.Models
{

    public partial class Movie : IDataErrorInfo
    {
        private Dictionary<string, string> _errors = new Dictionary<string, string>();

        partial void OnTitleChanging(string value)
        {
            if (value.Trim().Length == 0)
                _errors.Add("Title", "Title is required.");
        }

        partial void OnDirectorChanging(string value)
        {
            if (value.Trim().Length == 0)
                _errors.Add("Director", "Director is required.");
        }

    }
}

예를 들어 Title 속성에 빈 문자열을 할당하려고 하면 오류 메시지가 _errors라는 사전에 할당됩니다.

이 시점에서 타이틀 속성에 빈 문자열을 할당하고 프라이빗 _errors 필드에 오류가 추가될 때 실제로 아무 일도 일어나지 않습니다. 이러한 유효성 검사 오류를 ASP.NET MVC 프레임워크에 노출하려면 IDataErrorInfo 인터페이스를 구현해야 합니다.

IDataErrorInfo 인터페이스 구현

IDataErrorInfo 인터페이스는 첫 번째 버전부터 .NET 프레임워크의 일부였습니다. 이 인터페이스는 매우 간단한 인터페이스입니다.

public interface IDataErrorInfo
{
    string this[string columnName] { get; }

    string Error { get; }
}

클래스가 IDataErrorInfo 인터페이스를 구현하는 경우 ASP.NET MVC 프레임워크는 클래스의 instance 만들 때 이 인터페이스를 사용합니다. 예를 들어 홈 컨트롤러 만들기() 작업은 Movie 클래스의 instance 허용합니다.

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create([Bind(Exclude = "Id")] Movie movieToCreate)
{
    // Validate
    if (!ModelState.IsValid)
        return View();

    // Add to database
    try
    {
        _db.AddToMovieSet(movieToCreate);
        _db.SaveChanges();

        return RedirectToAction("Index");
    }
    catch
    {
        return View();
    }
}

ASP.NET MVC 프레임워크는 모델 바인더(DefaultModelBinder)를 사용하여 Create() 작업에 전달된 Movie의 instance 만듭니다. 모델 바인더는 HTML 양식 필드를 Movie 개체의 instance 바인딩하여 Movie 개체의 instance 만듭니다.

DefaultModelBinder는 클래스가 IDataErrorInfo 인터페이스를 구현하는지 여부를 검색합니다. 클래스가 이 인터페이스를 구현하는 경우 모델 바인더는 클래스의 각 속성에 대해 IDataErrorInfo.this 인덱서 를 호출합니다. 인덱서가 오류 메시지를 반환하는 경우 모델 바인더는 이 오류 메시지를 모델 상태에 자동으로 추가합니다.

DefaultModelBinder는 IDataErrorInfo.Error 속성도 확인합니다. 이 속성은 클래스와 연결된 속성이 아닌 특정 유효성 검사 오류를 나타내기 위한 것입니다. 예를 들어 Movie 클래스의 여러 속성 값에 따라 유효성 검사 규칙을 적용할 수 있습니다. 이 경우 Error 속성에서 유효성 검사 오류를 반환합니다.

목록 4의 업데이트된 Movie 클래스는 IDataErrorInfo 인터페이스를 구현합니다.

목록 4 - Models\Movie.cs(IDataErrorInfo 구현)

using System.Collections.Generic;
using System.ComponentModel;

namespace MvcApplication1.Models
{

    public partial class Movie : IDataErrorInfo
    {
        private Dictionary<string, string> _errors = new Dictionary<string, string>();

        partial void OnTitleChanging(string value)
        {
            if (value.Trim().Length == 0)
                _errors.Add("Title", "Title is required.");
        }

        partial void OnDirectorChanging(string value)
        {
            if (value.Trim().Length == 0)
                _errors.Add("Director", "Director is required.");
        }

        #region IDataErrorInfo Members

        public string Error
        {
            get
            {
                return string.Empty;
            }
        }

        public string this[string columnName]
        {
            get
            {
                if (_errors.ContainsKey(columnName))
                    return _errors[columnName];
                return string.Empty;
            }
        }

        #endregion
    }
}

목록 4에서 인덱서 속성은 _errors 컬렉션을 검사하여 인덱서에 전달된 속성 이름에 해당하는 키가 포함되어 있는지 확인합니다. 속성과 관련된 유효성 검사 오류가 없으면 빈 문자열이 반환됩니다.

수정된 Movie 클래스를 사용하기 위해 홈 컨트롤러를 수정할 필요가 없습니다. 그림 3에 표시된 페이지는 제목 또는 디렉터 양식 필드에 값을 입력하지 않을 때 발생하는 일을 보여 줍니다.

자동으로 작업 메서드 만들기

그림 03: 값이 누락된 양식(전체 크기 이미지를 보려면 클릭)

DateReleased 값의 유효성이 자동으로 검사됩니다. DateReleased 속성은 NULL 값을 허용하지 않으므로 DefaultModelBinder는 값이 없는 경우 이 속성에 대한 유효성 검사 오류를 자동으로 생성합니다. DateReleased 속성에 대한 오류 메시지를 수정하려면 사용자 지정 모델 바인더를 만들어야 합니다.

요약

이 자습서에서는 IDataErrorInfo 인터페이스를 사용하여 유효성 검사 오류 메시지를 생성하는 방법을 알아보았습니다. 먼저 Entity Framework에서 생성된 partial Movie 클래스의 기능을 확장하는 Partial Movie 클래스를 만들었습니다. 다음으로, Movie 클래스 OnTitleChanging() 및 OnDirectorChanging() 부분 메서드에 유효성 검사 논리를 추가했습니다. 마지막으로 이러한 유효성 검사 메시지를 ASP.NET MVC 프레임워크에 노출하기 위해 IDataErrorInfo 인터페이스를 구현했습니다.