[英]How do I write a custom validator in MVC3 for US or Canada zip code validation, based on the selected country?
[英]How do I do Sub Object Custom Validation mvc3
我有一個對象(標頭),其中包含子對象(詳細信息)的列表,在接受數據之前,我想對這些子對象進行自定義驗證。 我已經嘗試過ModelState.IsValid和TryValidateModel,但它似乎並未在子對象(僅標題對象)上觸發Validate方法。
因此,在提交時,我看到了標題的驗證動作,但沒有子對象的驗證動作。 然后,如果我執行TryValidateModel,我將再次看到(斷點)驗證方法在標頭上調用,但不在子對象上調用。
帶注釋的驗證(必須是數字,等等)似乎在子對象上起作用,而不是通過IValidatableObject接口添加的自定義邏輯。 任何幫助將不勝感激。
我創建一個屬性([ValidateObject]),它將驗證您放在類中的屬性,就像您認為應該做的那樣。
public class Personne
{
[ValidateObject]
public Address Address { get; set; }
//[...]
}
(地址是一個自定義類。)
它可以用於驗證:
子對象的集合。
[ValidateObject] public List<Address> Address { get; set; }
它支持多層次的部門,如果“地址”具有屬性為“ ValidateObject”的屬性為“ ZipCode”,則將對其進行驗證。
碼:
public class ValidateObjectAttribute : ValidationAttribute
{
public ValidateObjectAttribute()
{
}
private ValidationContext ValidationContext { get; set; }
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
this.ValidationContext = validationContext;
var results = new List<ValidationResult>();
try
{
var isIterable = this.IsIterable(value);
if (isIterable)
{
int currentItemPosition = -1;
foreach (var objectToValidate in value as IEnumerable<object>)
{
currentItemPosition++;
var resultTemp = ValidationsForObject(objectToValidate, true, currentItemPosition);
if (resultTemp != null)
results.AddRange(resultTemp);
}
if (results.Count <= 0)
results = null;
}
else
results = ValidationsForObject(value);
if (results != null)
{
//Build a validation result
List<string> memberNames = new List<string>();
results.ForEach(r => memberNames.AddRange(r.MemberNames));
var compositeResultsReturn = new CompositeValidationResult($"Validation for {validationContext.DisplayName} failed!", memberNames.AsEnumerable());
results.ForEach(r => compositeResultsReturn.AddResult(r));
return compositeResultsReturn;
}
}
catch (Exception) { }
return ValidationResult.Success;
}
private List<ValidationResult> ValidationsForObject (object objectToValidate, bool IsIterable = false, int position = -1)
{
var results = new List<ValidationResult>();
var contextTemp = new ValidationContext(objectToValidate, null, null);
var resultsForThisItem = new List<ValidationResult>();
var isValid = Validator.TryValidateObject(objectToValidate, contextTemp, resultsForThisItem, true);
if (isValid)
return null;
foreach (var validationResult in resultsForThisItem)
{
List<string> propNames = new List<string>();// add prefix to properties
foreach (var nameOfProp in validationResult.MemberNames)
{
if (IsIterable)
propNames.Add($"{this.ValidationContext.MemberName}[{position}].{nameOfProp}");
else
propNames.Add($"{this.ValidationContext.MemberName}.{nameOfProp}");
}
var customFormatValidation = new ValidationResult(validationResult.ErrorMessage, propNames);
results.Add(customFormatValidation);
}
return results;
}
private bool IsIterable(object value)
{
////COULD WRITE THIS, but its complicated to debug...
//if (value.GetType().GetInterfaces().Any(
//i => i.IsGenericType &&
//i.GetGenericTypeDefinition() == typeof(IEnumerable<>)))
//{
// // foreach...
//}
Type valueType = value.GetType();
var interfaces = valueType.GetInterfaces();
bool isIterable = false;
foreach (var i in interfaces)
{
var isGeneric = i.IsGenericType;
bool isEnumerable = i.GetGenericTypeDefinition() == typeof(IEnumerable<>);
isIterable = isGeneric && isEnumerable;
if (isIterable)
break;
}
return isIterable;
}
}
public class CompositeValidationResult : ValidationResult
{
private readonly List<ValidationResult> _results = new List<ValidationResult>();
public IEnumerable<ValidationResult> Results
{
get
{
return _results;
}
}
public CompositeValidationResult(string errorMessage) : base(errorMessage)
{
}
public CompositeValidationResult(string errorMessage, IEnumerable<string> memberNames) : base(errorMessage, memberNames)
{
}
protected CompositeValidationResult(ValidationResult validationResult) : base(validationResult)
{
}
public void AddResult(ValidationResult validationResult)
{
_results.Add(validationResult);
}
}
如果您的模型正確綁定,這將起作用:)
您可能想要添加必需的屬性,以確保對象本身不為null。
[Required]
希望對您有所幫助!
我想知道您的根對象是否有阻止子驗證的錯誤。 請參見使用批注和IValidatableObject進行遞歸驗證。此URL提到了該方案,還提供了從根目錄強制對子代進行驗證的代碼
根據發布觸發從根對象進行驗證
public IEnumerable Validate(ValidationContext validationContext)
{
var context = new ValidationContext(this.Details, validationContext.ServiceContainer, validationContext.Items);
var results = new List();
Validator.TryValidateObject(this.Details, context, results);
return results;
}
TryValidateObject似乎沒有觸發自定義驗證,只有數據批注? 我通過執行以下操作將詳細信息的驗證添加到標頭驗證中:
foreach (var detail in this.Details)
{
var validationResults = detail.Validate(validationContext);
foreach (var validationResult in validationResults)
{
yield return validationResult;
}
}
這在驗證方面起作用,但是UI沒有顯示錯誤消息。 即使我在UI上有ValidationMessagesFor。
驗證無法正常解決,這里: MVC3主詳細信息驗證未顯示
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.