I've got my model which contains some members:
public class Address
{
public Street { get; set;}
public City { get; set; }
public PostalCode { get; set; }
}
Now I've got my ValidationAttribute
with IsValid
method overrided like this:
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
var input = value as Address;
if (string.IsNullOrEmpty(input.City))
return new ValidationResult("City is required);
if (!string.IsNullOrEmpty(input.PostalCode))
if (string.IsNullOrEmpty(input.Street))
return new ValidationResult("Stret is required");
return ValidationResult.Success;
}
The problem is:
After validation my model state adds model error only to whole Adress member, but I need it to be added to specified members like city or street.
Any help with this will be appreciated... thanks!
you can add memberNames !
return new ValidationResult("City is required", new string[] { "City", "Street" });
EDIT : i've tested and found a solution : System.ComponentModel.IDataErrorInfo !! this doesn't work on the javascript client, but when submitting the result is what we attempted :) so keep using the ValidationResult with memberNames and :
public class myModel : System.ComponentModel.IDataErrorInfo
{
private Dictionary<string, List<ValidationResult>> errors;
private bool IsValidated = false;
private void Validate()
{
errors = new Dictionary<string, List<ValidationResult>>();
List<ValidationResult> lst = new List<ValidationResult>();
Validator.TryValidateObject(this, new ValidationContext(this, null, null), lst, true);
lst.ForEach(vr =>
{
foreach (var memberName in vr.MemberNames)
AddError(memberName, vr);
});
IsValidated = true;
}
private void AddError(string memberName, ValidationResult error)
{
if (!errors.ContainsKey(memberName))
errors[memberName] = new List<ValidationResult>();
errors[memberName].Add(error);
}
public string Error
{
get
{
if (!IsValidated)
Validate();
return string.Join("\n", errors
.Where(kvp => kvp.Value.Any())
.Select(kvp => kvp.Key + " : " + string.Join(", ", kvp.Value.Select(err => err.ErrorMessage)))
);
}
}
public string this[string columnName]
{
get
{
if (!IsValidated)
Validate();
if (errors.ContainsKey(columnName))
{
var value = errors[columnName];
return string.Join(", ", value.Select(err => err.ErrorMessage));
}
else
return null;
}
}
and now the current property is marked in error, and the memberNames too !
:D
Edit 2
In fact, you can keep simple DataAnnotations to inform client, and server side, you can add more complex business validation :
public class myModel : IValidatableObject
{
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (string.IsNullOrEmpty(input.City))
yield return new ValidationResult("City is required",new string[]{"prop1","prop2"});
if (!string.IsNullOrEmpty(input.PostalCode))
if (string.IsNullOrEmpty(input.Street))
yield return new ValidationResult("Stret is required");
}
note that the Validate method is called only when DataAnnotations are all valid !