10

I am trying to validate nested objects (not models in the MVC senss) using annotations and some custom code.

I found the following post useful

Using Data Annotations Validation Manually and Object Graphs

As suggested in an answer, I've created an extra routine in the container class to validate the nested object. Here's my modified test code

public class Customer : IValidatableObject
{
    public Customer()
    {
        Details = new CustomerDetails();
    }

    [Required]
    [MaxLength(2)]
    public string Name
    {
        get;
        set;
    }

    public CustomerDetails Details
    {
        get;
        private set;
    }

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        var context = new ValidationContext(this.Details, validationContext.ServiceContainer, validationContext.Items);
        var results = new List<ValidationResult>();
        Validator.TryValidateObject(this.Details, context, results);
        return results;
    }
}

However I have problems getting all the validation errors, even when calling TryValidateObject with validateAllProperties set to true.

        var context = new ValidationContext(cs, null, null);
        var results = new List<ValidationResult>();
        Validator.TryValidateObject(cs, context, results,true);

If there are any errors in the container, only these will show. Only when there are no errors in the container object, errors in the nested object will show. I suspect it has something to do with the Validate rouine returning a full list, and not being able to add to an (existing) list from the container(?)

Are there any modifications I can make to routine to get all errors to show?

Community
  • 1
  • 1
goorj
  • 443
  • 7
  • 15

1 Answers1

5

See this answer: https://stackoverflow.com/a/3400627/724944

So, there is an error in your class' atributes, and therefore Validate method doesn't get called. I suggest using CustomValidationAttribute like this:

[CustomValidation(typeof(Customer), "ValidateRelatedObject")]
public CustomerDetails Details
{
    get;
    private set;
}

public static ValidationResult ValidateRelatedObject(object value, ValidationContext context)
{
    var context = new ValidationContext(value, validationContext.ServiceContainer, validationContext.Items);
    var results = new List<ValidationResult>();
    Validator.TryValidateObject(value, context, results);

    // TODO: Wrap or parse multiple ValidationResult's into one ValidationResult

    return result;

}
Community
  • 1
  • 1
surfen
  • 4,644
  • 3
  • 34
  • 46
  • Ok, if I understand you correctly, "validateAllProperties" will only affect annotated properties, not a separate Validate routine? But I did try to implement your routine, but I have problems with what you left as TODO. As ValidateRelatedObject returns a single ValidationResult, (for a single annotated property), how can I have it push a potential list of errors (from the nested object) into the list of potential errors from the container objects? The original example seemed more promising in this regard as it returned a list. Your help is much appreciated! – goorj Dec 18 '11 at 10:48
  • In my project I simply enumerate all ValidationResult's and Merge errors into one string, separated by new line. Later, when I need to use it, I just split the error into multiple lines. You might also consider creating a class like MultiValidationResult which will store actual ValidationResult's and expose concatenated error. – surfen Dec 18 '11 at 12:45