ASP.NET MVC - Validation(2)



새로운맘으로 다시 시작하는 무책임 쎄스입니다. 그래서!!! 군말없이 바로 시작하도록 하겠습니다.

IErrorDataInfo 인터페이스로 유효성검사하기

IErrorDataInfo 인터페이스를 이용하여 유효성 검사를 어떻게 하는지 알아보도록 하겠습니다.

일단 해보자

TelDir 테이블을 생성하고, 엔티티 프레임워크로 모델 클래스를 생성합니다. 그러면, 다음과 같은 엔티티가 표현되겠죠?
하도 많이 해서 지겨우실겁니다-_-;; 다른 예제를 생각해야하는데.. 제가 게을러서; 아이디어도 없고;


컨트롤러 클래스 작성하기

다음의 컨트롤러 소스를 보시죠.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Validation1.Models;

namespace Validation1.Controllers
{
    [HandleError]
    public class HomeController : Controller
    {
        private MvcDBEntities _db;

        public HomeController()
        {
            _db = new MvcDBEntities();
        }

        public ActionResult Index()
        {
            ViewData["Message"] = "Welcome to ASP.NET MVC!";
            return View();
        }
              
        public ActionResult Create()
        {
            return View();
        }

        [HttpPost]
        public ActionResult Create([Bind(Exclude="Id")] TelDir dir)
        {          
            if (!ModelState.IsValid)
                return View();
           try
            {
                _db.AddToTelDir(dir);
                _db.SaveChanges();

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


마찬가지로 Create() 액션 메쏘드가 두개가 있습니다. 하나는 새롭게 전화번호를 추가할수 있게 해줄 HTML 폼을 그려줄 액션이고요, 다른 하나는 디비에 인서트 작업을 할 액션이죠. 다들 아실줄 압니다.
첫번째 액션에서 폼을 summit하게되면 두번째 액션이 호출되는겁니다.

두번째 액션(POST)에서의 소스를 보게되면,

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


IsValid 속성은 유효성 에러가 있을시에 false를 반환합니다.

파샬 클래스 만들기

TelDir 클래스는 엔티티 프레임워크에 의해 생성되었습니다. 생성된 MvcModel.Designer.cs 파일을 열어보죠.


TelDir 클래스는 partial 클래스입니다. 이는 같은 이름으로 TelDir 파샬 클래스를 추가해서 기능을 확장할수 있다는 의미가 되죠.
새로운 파샬 클래스에 유효성 검사 로직을 추가해보도록 하겠습니다.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel;

namespace Validation1.Models
{
    public partial class TelDir
    {

    }
}


자, 퍄살클래스를 Model 폴더에 생성했습니다. 이 클래스에 추가될 메쏘드나 속성들은 엔티티 프레임워크에 의해 생성된 TelDir 클래스의 한 부분이 될것입니다.

OnChanging, OnChanged 파샬 메쏘드 추가하기

엔티티 프레임워크가 엔티티 클래스를 생성할때, 엔티티 프레임워크는 자동적으로 파샬 메쏘드를 추가합니다. 클래스의 각 속성과 대응하는 OnChanging, Onchanged 파샬 메쏘드를 말이죠.

예를들어, 이 TelDir 클래스의 경우 엔티티 프레임워크는 다음과 같은 메쏘드를 생성합니다.

* OnIdChanging, OnIdChanged
* OnNameChanging, OnNameChanged
* OnPhoneChanging, OnPhoneChanged
* OnSpeedDialChanging, OnSpeedDialChanged
* OnWdateChanging, OnWdateChanged

OnChanging 메쏘드의 경우, 대응되는 속성을 바뀌기 바로 직전에 호출이 됩니다. 당연히, OnChanged 메쏘드는 속성이 드바뀐후에 호출이 되겠죠.

이들 파샬 메쏘드의 이점을 살려서, TelDir 클래스에 유효성 검사 로직을 추가하겠습니다.
다음과 같이 해보시죠.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel;

namespace Validation1.Models
{
    public partial class TelDir : IDataErrorInfo
    {
        private Dictionary<string, string> _errors = new Dictionary<string, string>();

        partial void OnNameChanging(string value)
        {
            if (string.IsNullOrEmpty(value))
                _errors.Add("Name", "이름을 입력하시오.");
        }

        partial void OnPhoneChanging(string value)
        {
            if (string.IsNullOrEmpty(value))
                _errors.Add("Phone", "전화번호를 입력하시오.");
        }
    }
}


예를들어, Name 을 빈 문자열로 할당을 하게되면, 에러 메시지는 Name이라는 이름으로 _errors 에 추가됩니다.
현재 상태만으로는 private인 _error에 에러를 넣어봤자 아무 일도 생기지 않습니다. (이거참~ㅡ.ㅡ) 그래서, 해야할일은 뭣이냐?
바로, IDataErrorInfo 인터페이스를 구현하는 것이죠. 이를 구현함으로써, 유효성 에러 메시지가 ASP.NET MVC 프레임워크에 노출이 되는 것입니다.

IDataErrorInfo 인터페이스 구현하기

IDataErrorInfo 인터페이스는 닷넷 프레임워크 첫 버전부터 있었던 아주 간단한 인터페이스입니다.

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

클래스에 IDataErrorInfo 인터페이스를 구현하면 MVC 프레임워크는 클래스에 인스턴스가 생성될때 이 인터페이스를 사용할 것입니다. 예를들어, 위 컨트롤러의 Create() 포스트 메쏘드를 보시면,

public ActionResult Create([Bind(Exclude="Id")] TelDir dir)

ASP.NET MVC 프레임워크는 모델바인더(DefaultModelBinder)에 의해 TelDir의 인스턴스를 생성합니다. 모델 바인더는 HTML 폼 필드를 TelDir 객체의 인스턴스로 만들 책임이 있습니다.

DefaultModelBinder는 클래스가 IDataErrorInfo 인터페이스를 구현했는지 안했는지를 찾습니다. 클래스가 이를 구현했다면, 모델바인더는 그 클래스의 각 속성들을 IDataErrorInfo.this 인덱서를 통해 호출합니다. 이 인덱서는 에러메시지를 리턴하고, 모델 바인더는 에러메시지를 모델 스테이트에 자동적으로 추가합니다.

자, IDataErrorInfo 인터페이스를 구현해볼까요?
인터페이스 생성시 팁을 추가하자면, 해당 인터페이스에서 커서를 갖다댄후 ' Ctrl + .  '을 클릭하면 쉽게 생성할 수 있습니다.


생성한 후 조금만 수정하면 다음과 같은 소스를 보실수 있습니다.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel;

namespace Validation1.Models
{
    public partial class TelDir : IDataErrorInfo
    {
        private Dictionary<string, string> _errors = new Dictionary<string, string>();

        partial void OnNameChanging(string value)
        {
            if (string.IsNullOrEmpty(value))
                _errors.Add("Name", "이름을 입력하시오.");
        }

        partial void OnPhoneChanging(string value)
        {
            if (string.IsNullOrEmpty(value))
                _errors.Add("Phone", "전화번호를 입력하시오.");
        }

        partial void OnSpeedDialChanging(decimal? value)
        {
            if (value.HasValue)
            {
               if(value < 1 || value > 99)
                   _errors.Add("SpeedDial", "값의 범위를 벗어났습니다.(1~99)");
            }
        }

        #region IDataErrorInfo 멤버

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

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

        #endregion       
    }
}

인덱서는 _errors 컬렉션을 체크하여 프로퍼티 이름과 대응하는 키가 있으면 그것을 리턴하고, 연관된 에러 메시지가 없으면 빈문자열을 리턴합니다.

수정된 TelDir 클래스를 사용하기 위해 컨트롤러는 수정할 필요가 없습니다.  다음은 에러가 났을 경우에 표시되는 화면입니다.


잘되죠?^^; 유효성 검사만으로도 공부할 것이 많네요. ㅎㄷㄷ;;

참고 : http://www.asp.net/mvc/tutorials/validating-with-the-idataerrorinfo-interface--cs

'.NET > MVC Basic' 카테고리의 다른 글

ASP.NET MVC - Validation(4)  (0) 2010.05.27
ASP.NET MVC - Validation(3)  (0) 2010.05.26
ASP.NET MVC - Validation(1)  (0) 2010.05.24
ASP.NET MVC - Model(2)  (4) 2010.04.04
ASP.NET MVC - Model(1)  (0) 2010.03.31