asp.net mvc에서 IDataErrorInfo 사용
-
19-09-2019 - |
문제
IDataErrorInfo 인터페이스를 사용하려고 하는 간단한 주소 입력 앱이 있습니다. asp.net 사이트에 설명되어 있습니다..
독립적으로 유효성을 검사할 수 있는 항목에는 적합하지만 일부 항목이 다른 항목에 종속되는 경우에는 적합하지 않습니다.예를 들어 우편번호 확인은 국가에 따라 다릅니다.
private string _PostalCode;
public string PostalCode
{
get
{
return _PostalCode;
}
set
{
switch (_Country)
{
case Countries.USA:
if (!Regex.IsMatch(value, @"^[0-9]{5}$"))
_errors.Add("PostalCode", "Invalid Zip Code");
break;
case Countries.Canada:
if (!Regex.IsMatch(value, @"^([a-z][0-9][a-z]) ?([0-9][a-z][0-9])$", RegexOptions.IgnoreCase))
_errors.Add("PostalCode", "Invalid postal Code");
break;
default:
throw new ArgumentException("Unknown Country");
}
_PostalCode = value;
}
}
따라서 국가를 설정한 후에만 우편번호를 확인할 수 있지만 그 순서를 제어할 수 있는 방법은 없는 것 같습니다.
IDataErrorInfo의 오류 문자열을 사용할 수 있지만 필드 옆의 Html.ValidationMessage에는 표시되지 않습니다.
해결책
보다 복잡한 비즈니스 규칙 검증의 경우 유형 검증보다는 서비스 계층과 같은 디자인 패턴을 구현하는 것이 더 나을 수 있습니다.ModelState를 확인하고 논리에 따라 오류를 추가할 수 있습니다.
여기에서 Rob Conroy의 패턴 예를 볼 수 있습니다.
http://www.asp.net/learn/mvc/tutorial-29-cs.aspx
데이터 주석에 관한 이 문서도 유용합니다.
http://www.asp.net/learn/mvc/tutorial-39-cs.aspx
도움이 되었기를 바랍니다.
다른 팁
단순한 데이터 주석 모델을 넘어 더욱 복잡한 검증을 위해 제가 찾은 최고의 솔루션은 다음과 같습니다.
구현하려는 노력이 나 혼자가 아닐 것이라고 확신합니다. IDataErrorInfo
구현해야 할 두 가지 방법만 생성되었음을 확인했습니다.잠깐만요. 이제 거기로 가서 모든 것에 대해 처음부터 나만의 맞춤 루틴을 작성해야 할까요?또한 모델 수준에서 검증할 사항이 있으면 어떻게 됩니까?뭔가 하고 싶지 않은 이상 사용하기로 결정하면 스스로 판단하는 것 같습니다. 이와 같이 또는 이것 IDataErrorInfo 구현 내에서.
질문자와 똑같은 문제가 발생했습니다.US Zip을 확인하고 싶었지만 국가가 US로 선택된 경우에만 가능했습니다.분명히 모델 수준 데이터 주석은 우편번호가 오류로 빨간색으로 강조 표시되지 않기 때문에 좋지 않습니다.[클래스 수준 데이터 주석의 좋은 예는 PropertiesMustMatchAttribute 클래스의 MVC 2 샘플 프로젝트에서 찾을 수 있습니다].
해결책은 매우 간단합니다.
먼저 global.asax에 모델바인더를 등록해야 합니다.원한다면 클래스 수준 [속성]으로 이 작업을 수행할 수 있지만 global.asax에 등록하는 것이 더 유연하다고 생각합니다.
private void RegisterModelBinders()
{
ModelBinders.Binders[typeof(UI.Address)] = new AddressModelBinder();
}
그런 다음 modelbinder 클래스를 만들고 복잡한 유효성 검사를 작성합니다.개체의 모든 속성에 대한 전체 액세스 권한이 있습니다.이 실행됩니다 ~ 후에 모든 데이터 주석이 실행되었으므로 유효성 검사 속성의 기본 동작을 되돌리려는 경우 언제든지 모델 상태를 지울 수 있습니다.
public class AddressModelBinder : DefaultModelBinder
{
protected override void OnModelUpdated(ControllerContext controllerContext,
ModelBindingContext bindingContext)
{
base.OnModelUpdated(controllerContext, bindingContext);
// get the address to validate
var address = (Address)bindingContext.Model;
// validate US zipcode
if (address.CountryCode == "US")
{
if (new Regex(@"^\d{5}([\-]\d{4})?$", RegexOptions.Compiled).
Match(address.ZipOrPostal ?? "").Success == false)
{
// not a valid zipcode so highlight the zipcode field
var ms = bindingContext.ModelState;
ms.AddModelError(bindingContext.ModelName + ".ZipOrPostal",
"The value " + address.ZipOrPostal + " is not a valid zipcode");
}
}
else {
// we don't care about the rest of the world right now
// so just rely on a [Required] attribute on ZipOrPostal
}
// all other modelbinding attributes such as [Required]
// will be processed as normal
}
}
이것의 장점은 기존의 모든 유효성 검사 속성([필수], [EmailValidator], [MyCustomValidator])이 무엇이든 여전히 작동한다는 것입니다.
원하는 대로 모델 바인더에 추가 코드를 추가하고 필드를 설정하거나 모델 수준의 ModelState 오류를 설정할 수 있습니다.
저에게는 Address
메인 모델의 자식입니다 - 이 경우 CheckoutModel
이는 다음과 같습니다.
public class CheckoutModel
{
// uses AddressModelBinder
public Address BillingAddress { get; set; }
public Address ShippingAddress { get; set; }
// etc.
}
그렇기 때문에 내가 해야 할 일은 bindingContext.ModelName
+ ".ZipOrPostal"
'BillingAddress.ZipOrPostal' 및 'ShippingAddress.ZipOrPostal'에 대해 모델 오류가 설정됩니다.
추신.'단위 테스트 유형'의 모든 의견에 감사드립니다.이것이 단위 테스트에 미치는 영향에 대해서는 잘 모르겠습니다.
오류 문자열, IDataErrorInfo 및 Html.ValidationMessage에 대한 설명과 관련하여 개체 수준과 개체 수준을 표시할 수 있습니다.다음을 사용하는 필드 수준 오류 메시지:
Html.ValidationMessage("address", "Error")
Html.ValidationMessage("address.PostalCode", "Error")
컨트롤러에서 [Bind(Prefix = "address")]를 사용하여 객체에 대한 게시 메서드 핸들러 매개변수를 장식합니다.HTML에서 입력 필드의 이름을 다음과 같이 지정하십시오.
<input id="address_PostalCode" name="address.PostalCode" ... />
나는 일반적으로 Html 도우미를 사용하지 않습니다.id와 name 사이의 명명 규칙에 유의하세요.