네번째 시간입니다..헥헥..
이전글 에 밝혔듯이 이번 시간엔 Class에 정의 하는 특성에 대해서 알아 보도록 하겠습니다.
/// <summary> /// <para>두개의 문자열의 값이 같은지 검사하는 검사기 특성입니다.</para> /// </summary> /// <remarks> 2010.12.28 - Prototype - 이방은(www.bangsil.net) </remarks> [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)] public sealed class SamePasswordAttirbute : ValidationAttribute, ICustomRule { /// <summary> /// 첫번째 값을 가리키는 속성의 이름을 가져오거나 설정합니다. /// </summary> /// <value>The first name of the property.</value> public string FirstPropertyName { get; set; } /// <summary> /// 두번째 값을 가리키는 속성의 이름을 가져오거나 설정합니다. /// </summary> /// <value>The name of the second property.</value> public string SecondPropertyName { get; set; } /// <summary> /// 오류가 발생한 데이터 필드를 기반으로 오류 메시지에 형식을 적용합니다. /// </summary> /// <param name="name">오류가 발생한 데이터 필드의 이름입니다.</param> /// <returns>형식 지정된 오류 메시지의 인스턴스입니다.</returns> public override string FormatErrorMessage(string name) { return String.Format(this.ErrorMessageString); } /// <summary> /// 개체의 지정된 값이 유효한지 여부를 확인합니다. /// </summary> /// <param name="value"><see cref="T:System.ComponentModel.DataAnnotations.ValidationAttribute"/>가 선언된, 지정된 유효성 검사 개체의 값입니다.</param> /// <returns>지정된 값이 유효하면 true이고, 그렇지 않으면 false입니다.</returns> public override bool IsValid(object value) { PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(value); object firstValue = properties.Find(this.FirstPropertyName, true).GetValue(value); object secondValue = properties.Find(this.SecondPropertyName, true).GetValue(value); return Object.Equals(firstValue, secondValue); } #region ICustomRule 멤버 /// <summary> /// Toes the custom rule. /// </summary> /// <returns></returns> public CustomRule ToCustomRule() { return new CustomRule("validateSamePassword", new { this.FirstPropertyName, this.SecondPropertyName }, this.FormatErrorMessage(null)); } #endregion }
14행을 보게 되면 AttributeUsage 특성의 AttributeTargets 속성에 Class 라고 지정되어 있는걸 확인 할 수 있습니다. 즉 클래스에서 사용하는 특성이라는 것이겠죠.
11행의 주석에 있듯이 이 특성은 2개의 문자열이 같은지 검사하는 특성입니다.
비밀번호 확인에서 사용되고 있는 특성이지요.
주어진 속성은 2개가 있습니다. FirstPropertyName과 SecondPropertyName 이 있네요.
44행의 IsValid 메서드를 보시죠.
2개의 속성에 주어진 값, 이 값은 비교를 할 속성의 이름이 되겠네요.
이름으로 해당 속성의 값을 얻어 와서 같은지 비교하는 코드가 되겠습니다.
그 결과 같으면 true , 그렇지 않으면 false가 되겠네요.
58행의 메서드에서는 클라이언트 스크립트로 넘겨줄 매개변수를 정해줍니다.
validateSavePassword 라는 함수와 2개의 매개변수를 넘겨 줍니다.
이제 클라이언트 스크립트 메서드를 봅시다.
function validateSamePassword(value, element, params) { return value != null && value == $('#' + params.FirstPropertyName).val(); };
뭐 초 간단합니다..^^;
이 특성의 사용법은 아래와 같습니다.
[SamePasswordAttirbute(FirstPropertyName = "Password", SecondPropertyName = "ConfirmPassword", ErrorMessage = "비밀번호와 비밀번호 확인의 값이 다릅니다.")] public class Register { [Required(ErrorMessage = "비밀번호를 입력하여 주십시오.")] [DataType(DataType.Password)] [MaxMinStringLength(16, ErrorMessage = "비밀번호의 글자수는 {0}보다 크고 {1}보다 작아야 합니다.")] [DisplayName("비밀번호")] public string Password { get; set; } [Required(ErrorMessage = "비밀번호 확인을 입력하여 주십시오.")] [DataType(DataType.Password)] [MaxMinStringLength(16, ErrorMessage = "비밀번호의 글자수는 {0}보다 크고 {1}보다 작아야 합니다.")] [DisplayName("비밀번호 확인")] public string ConfirmPassword { get; set; } }
이해 되시죠?
여기 까지는 Field나 Property에 붙는 특성과 같습니다.
실제로 여기까지 해 놓고 컴파일후 실행을 해보면..클라이언트의 Validation 체크는 하지 않지만 서버의 Validation 체크는 하는 걸 보실수 있습니다.
클래스에 적용하는 Validator의 경우에는 asax 파일에 추가로 RuleProvider를 등록을 해주어야 합니다.
이제 그러한 RuleProvider를 생성해 보도록 하겠습니다.
/// <summary> /// <para><see cref="SamePasswordAttribute"/> 특성을 클라이언트 코드에서도 사용할 수 있게 설정하는 <see cref="IRulesProvider"/>의 파생 클래스입니다.</para> /// </summary> /// <remarks> 2010.12.28 - Prototype - 이방은(www.bangsil.net) </remarks> public class SamePasswordRulesProvider : CachingRulesProvider { /// <summary> /// Gets the rules from type core. /// </summary> /// <param name="type">The type.</param> /// <returns></returns> protected override RuleSet GetRulesFromTypeCore(Type type) { IEnumerable<SamePasswordAttirbute> comparisonRules = type.GetCustomAttributes(typeof(SamePasswordAttirbute), true).Cast<SamePasswordAttirbute>(); return new RuleSet(comparisonRules.ToLookup(x => x.SecondPropertyName, x => (Rule)x.ToCustomRule())); } }
CachingRuleProvider는 xVal에 있는 클래스가 되겠습니다.
여기서 GetRulesFromTypeCore() 메서드만 재정의 해 주시면 되겠습니다.
그리고 마지막으로 이 RuleProvider를 global.asax 파일에 등록해 주시면 되겠네요.
protected void Application_Start() { AreaRegistration.RegisterAllAreas(); RegisterRoutes(RouteTable.Routes); ControllerBuilder.Current.SetControllerFactory(new CastleWindsorControllerFactory()); ActiveRuleProviders.Providers.Add(new SamePasswordRulesProvider()); ActiveRuleProviders.Providers.Add(new RestrictDateRulesProvider()); ActiveRuleProviders.Providers.Add(new RestrictValueRulesProvider()); ActiveRuleProviders.Providers.Add(new DateCompareRulesProvider()); }
위 9행 처럼 말이지요..
이렇게 하고 컴파일후 실행을 해보면 html 코드 상의 xVal.AttachValidator() 스크립트 블럭내부에
{"RuleName":"Custom","RuleParameters":{"Function":"validateSamePassword","Parameters":"{\"FirstPropertyName\":\"Password\",\"SecondPropertyName\":\"ConfirmPassword\"}"},"Message":"비밀번호와 비밀번호 확인의 값이 다릅니다."}]}
와 같은 코드 블럭이 추가됩니다.
다음 시간은 마지막시간으로 ..
xVal과 같이 배포된 xVal.jquery.validate.js에 대해 아주..간략하게만 살펴 보도록 하겠습니다.