Visual Studio 2010 공식 팀 블로그 @vsts2010

Posted by 박세식(쎄스)
모기와의 사투를 버린 끝에 이제야 컴퓨터 앞에 앉아 글을 쓸 수 있게 되네요(새벽 1시네요ㅡ.ㅡ) 아흑.
비록 눈이 따갑고 눕고 싶지만, 이제는 정말 제 자신과의 약속을 지키기 위해 한자 한자 적어나가렵니다.^^

지난 시간에 유효성 검사에 대해 살펴봤는데요. 이제 본론으로 넘어와서 적용해봐야겠죠?

유효성 검사 적용하기

저희가 USER 모델을 생성할때 엔터티 프레임워크(엔티티가 입에 붙었는데 한글판에 엔터티라고 명시되어있네요;;)를 통해 생성한 것 다들 기억하시죠? 엔터티 프레임워크의 경우 자동으로 모델 클래스를 생성해 주는 것도 다들 아실겁니다. 또한, 엔터티 프레임워크로 생성된 모델클래스를 직접적으로 컨트롤 할수 없다는 것도..
그렇다면 유효성 검사 부분은 도대체 어디다 둬야 한단 말이냐?

파샬 & 메타데이타 클래스 생성하기

메타 데이타 클래스를 만들어야 합니다. 또한 USER 모델에 해당하는 파샬 클래스도 생성해야합니다.
파샬 클래스의 경우 여러 파일, 여러 부분에 멤버나 메쏘드 등의 정의를 각각 두면 컴파일시에 이들 모두를 결합하게 되죠. 다들 아시는 내용!
여기서 잠깐, 엔터티 프레임워크로 생성된 모델 클래스의 소스를 잠깐 살펴보면,


모델 클래스가 파샬 클래스로 정의 되어 있는 것을 확인할 수 있습니다. 아~ 이러면 자동 생성된 이 모델 클래스는 건들 필요 없이 파샬 클래스를 하나 더 추가해서 그곳에다가 우리가 필요한 정의를 내려주면 되겠구나~ 라는 생각이 팍팍 드시죠?

그래서 추가해봤습니다. 동일한 이름의 모델 클래스를 하나 만들어 보죠. 그리고, 메타 데이타 클래스도 같이 만들겠습니다.

using System.ComponentModel.DataAnnotations;
using System.ComponentModel;

namespace MvcSite.Models

    [MetadataType(typeof(USERMetaData))]
    public partial class USER
    {      
    }

    public class USERMetaData
    {
        [Required(ErrorMessage="아이디 입력하셔야죠!")]
        [StringLength(10)]
        public object ID { get; set; }

        [Required(ErrorMessage="이름 입력하셔야죠!")]
        public object NAME { get; set; }
               
        [Required(ErrorMessage="패스워드 입력하셔야죠!")]       
        public object PWD { get; set; }
              
        [Required(ErrorMessage="이메일 입력하셔야죠!")]
        [RegularExpression(@"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$",
                                                             ErrorMessage = "올바른 이메일 형식이 아닙니다.")]
        public object EMAIL { get; set; }
    }
}

메타 데이터의 경우 테이블의 필드값을 대신합니다. 즉 모델과 같아야 합니다.
메타 데이터를 만든 후 파샬로 된 모델(USER) 클래스에 MetadataTypeAttribute를 통해 USERMetaData을 정의합니다. 이렇게하면 1차작업이 완료됩니다. 실행해 보시면 잘 돌아갑니다. 확인페이지는 따로 보여드리지 않겠습니다^^ 글이 너무 길어지면 지루해지겠죠?

모델에 없는 필드 확인하기

우리는 패스워드 확인 필드를 갖고 있습니다. 필수값이고 비교도 해야하지만 테이블에는 없는 필드죠. DataAnnotation을 통해 나머지 필드들은 각각 비교는 했는데, 패스워드 확인 필드는 어떻게~ 어떻게~ 어떡하면 되냐고~ 띠리링~ 그냥 만들어!

헉. 뭐 만들면 되죠;;;
일단, ValidationAttribute를 상속 받는 PropertiesMatchAttribute라는 이름의 두 값을 비교할 커스텀한 DataAnnotation 클래스를 만듭니다. 중요한건 검사를 담당하게될 IsValid 메쏘드를 오버라이드해야합니다.


이렇게 만든 후에, 생성한 USER 클래스를 수정하도록 하겠습니다.

    [PropertiesMatchAttribute("PWD", "CPWD",
                                         ErrorMessage = "패스워드 확인 안하실거에요?!")]

    [MetadataType(typeof(USERMetaData))]
    public partial class USER
    {
        [Required(ErrorMessage = "패스워드 확인 입력하셔야죠!")] 
       public string CPWD { get; set; }
    }

    public class USERMetaData
    {
        [Required(ErrorMessage="아이디 입력하셔야죠!")]
        [StringLength(10)]
        public object ID { get; set; }

        [Required(ErrorMessage="이름 입력하셔야죠!")]
        public object NAME { get; set; }
               
        [Required(ErrorMessage="패스워드 입력하셔야죠!")]       
        public object PWD { get; set; }
              
        [Required(ErrorMessage="이메일 입력하셔야죠!")]
        [RegularExpression(@"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$",
                                                            ErrorMessage = "올바른 이메일 형식이 아닙니다.")]
        public object EMAIL { get; set; }
    }

USER 클래스에 커스텀한 DataAnnotation 정의를 추가했고요, 패스워드 확인 필드를 필수값으로 정의하였습니다.
여기까지 잘 오셨죠? 실행해 보도록 하겠습니다.


위 결과물은 모든 필드에 입력을 안하고 submit을 했을 경우고, 아래 결과물은 패스워드를 다르게 입력 했을 경우입니다.


일단 원하는대로 출력되는 것을 확인했습니다.

역시 급정리요

이번시간 역시 유효성 검사 부분을 다뤘고요, 메타 데이터와 파샬 클래스를 이용한 유효성 검사를 살펴봤습니다.
정말 간단한 내용인데 쓰다보면 길어지네요;; 더 간단하게 필요한 메시지만 전달하도록 노력하겠습니다.

참조 : http://byatool.com/mvc/custom-data-annotations-with-mvc-how-to-check-multiple-properties-at-one-time
크리에이티브 커먼즈 라이선스
Creative Commons License

댓글을 달아 주세요

  1. 유효성체크를 이렇게도 하는군요. 잘보고 갑니당...

  2. 멍돌이 2010/06/25 12:05

    요번글도 잘보고 갑니다 ㅎㅎㅎㅎㅎ이글을 참고해서 제 프로젝트의 유효성 검사쪽을 좀 수정해야겠네여 ㅎㅎㅎ

  3. 1번 강좌글부터 따라해보고 있습니다.
    지난 강좌까지 어렵게 따라해왔는데, 여기서 막히네요.
    위에서 처럼 Models에 USER에 대한 Metadata를 정의하여 추가하였는데,
    모두 빈칸으로 두고 가입 버튼을 누르게 되면, 첫번째 빈칸이 되는 필드에서 "This property can not be set to a null value" exception이 발생하네요. Metadata에 지정한 에러메세지가 안나오네요. 뭐가 잘못 되었을까요? 혹시 샘플 프로젝트를 올려주실 수 는 없는지...

    • 안녕하세요. 너무 늦은 답변이라 뭐라 드릴말씀이 없네요;; 이 문제는 일단 디버그 모드일때 발생하고요 릴리즈 모드에서는 발생하지 않습니다. 만약 디버깅 모드에서도 처리를 하시려면 파샬클래스의 각 필드에 [DisplayFormat(ConvertEmptyStringToNull = false)] 이것을 추가하시면 됩니다. 이 annotation의 경우는 바인더가 빈값을 널로 변환시키지 않도록 하는 것입니다.

  4. 안녕하세요. 저도 블로그 내용 잘 보고 있습니다. 그런데 partial class 추가하고 유효성 검사를 하려고 텍스트박스 내용을 빈칸으로 해서 클릭을 하면 사용자코드에서 ConstraintException이 처리되지 않았습니다 라는 에외가 발생하는데요. 아무리 찾아봐도 이유를 잘 모르겠어요...알려주시면 고맙겠습니다..ㅠㅠ

    • 안녕하세요. 위에도 댓글을 달았지만(너무 늦었죠;;) 릴리즈모드에서는 정상 작동합니다. 이 exception 의 경우에는 엔터티 프레임워크가 ASP.NET MVC 프레임워크에게 해당 필드가 제약조건(null 허용 안함) 을 만족시키지 못했다고 통보하는 예외입니다. 유효성 검사에는 바인딩 이전(PreBinding), 이후(PostBinding)가 있는데요. submit(PostBinding)시에 유효성 검사를 하려했지만, 이전에 빈값으로 넘어온 값이 널(null) 값으로 변환되면서 바인더가 널값을 허용하지 않는 필드에 널값을 세팅하려는데서 발생한 것입니다. 필드에 [DisplayFormat(ConvertEmptyStringToNull = false)] 을 추가하시거나 릴리즈 모드에서 진행해보세요^^ 읽어주셔서 감사합니다.

  5. 안녕하세요 블로그 잘 보고 mvc 공부하고 있습니다. 예제를 보고 진행하는데
    위에 말씀하신대로 release 모드에 USERMetaData class에 [DisplayFormat(ConvertEmptyStringToNull = false)] 이 부분을 추가하고 실행을 하게 되면 빈값으로 해도 JoinSuccess로 페이지 이동은 일어나기는 하나 유효성 검사는 일어나지 않게됩니다.
    혹시 join.aspx 파일도 create.aspx 처럼 마크업을 바꿔주어야 하나요 또한 MemberController에 ModelState로 조건문을 추가해 줘야하는지요

    공부 열심히하고 있습니다 (__)