I'm using xVal in my ASP.NET MVC application, which is great in general. Following Steve Sanderson's blog post, I created a DataAnnotationsValidationRunner to do server-side validation of attributed objects. This works great for a simple class. e.g. Person:
public static class DataAnnotationsValidationRunner
{
public static IEnumerable<ErrorInfo> GetErrors(object o)
{
return from prop in TypeDescriptor.GetProperties(o).Cast<PropertyDescriptor>()
from attribute in prop.Attributes.OfType<ValidationAttribute>()
where !attribute.IsValid(prop.GetValue(o))
select new ErrorInfo(prop.Name, attribute.FormatErrorMessage(string.Empty), o);
}
}
public class Person
{
[Required(ErrorMessage="Please enter your first name")]
public string FirstName { get; set; }
[Required(ErrorMessage = "Please enter your last name")]
public string LastName { get; set; }
}
However, if I add an Address property to this person, and mark the Address class with DataAnnotation attributes, they will not be validated. e.g.
public class Person
{
[Required(ErrorMessage="Please enter your first name")]
public string FirstName { get; set; }
[Required(ErrorMessage = "Please enter your last name")]
public string LastName { get; set; }
public Address Address { get; set; }
}
public class Address
{
[Required(ErrorMessage="Please enter a street address")]
public string Street { get; set; }
public string StreetLine2 { get; set; }
[Required(ErrorMessage = "Please enter your city")]
public string City { get; set; }
[Required(ErrorMessage = "Please enter your state")]
public string State { get; set; }
[Required(ErrorMessage = "Please enter your zip code")]
public string Zip { get; set; }
public string Country { get; set; }
}
One problem is that the DataAnnotationValidationRunner doesn't walk down the complex child properties. Also, if those errors are added to an errors collection, they still need to get prefixed correctly when added to the model state. For example. The Person errors are added like this:
catch (RulesException ex)
{
ex.AddModelStateErrors(ModelState, "person");
}
I think the Address rules exceptions would need to be prefixed with "person.address". Is there a supported way of handling child object validation with xVal, or would creating a flattened data transfer object be the only solution?