Validating Object Graphs

May 16, 2013 at 3:01 PM
Edited May 16, 2013 at 3:02 PM
I see how you can re-use a validator for Complex Properties and Collections, but how will it work when the reference is bi-directional? Will the example below produce an infinite loop, and if so what is the best way to handle this?
public class Customer {
  public string Name { get; set; }
  public Address Address { get; set; }
}

public class Address {
  public string Line1 { get; set; }
  public string Line2 { get; set; }
  public string Town { get; set; }
  public string County { get; set; }
  public string Postcode { get; set; }
  public Customer Customer { get; set; }
}

public class AddressValidator : AbstractValidator<Address> {
  public AddressValidator() {
    RuleFor(address => address.Postcode).NotNull();
    RuleFor(address => address.Customer).SetValidator(new CustomerValidator());
    //etc
  }
}

public class CustomerValidator : AbstractValidator<Customer> {
  public CustomerValidator() {
    RuleFor(customer => customer.Name).NotNull();
    RuleFor(customer => customer.Address).SetValidator(new AddressValidator());
  }
} 
May 16, 2013 at 5:14 PM
Edited May 16, 2013 at 5:27 PM
Update: I just tried this and got a StackOverflow exception like I expected. Is there a feature/setting that I'm missing that makes this work? Maybe by using the When method? It seems like a person would need to keep track of what has been validated and use the When method to not validate a 2nd time. However, I'm not sure how one would capture what has already been validated. It's almost as if a "When Validating" event needs to be available.
Coordinator
May 17, 2013 at 8:53 AM
Hi

Yes, this will indeed cause a stackoverflow. Your best bet is either to remove one of the calls to SetValidator, and perform the validation manually when necessary or put one of the SetValidator calls inside a RuleSet and then explicitly choose when you want to execute it.

Jeremy
May 17, 2013 at 3:41 PM
It appears the StackOverflow is happening in the constructor while wiring up the validators instead of in the validators themselves.

Is it possible to mark an entity as validated so it doesn't wire up the validator a second time? Then I could wrap all the validators in a When condition?

Just some context: I'm generating my POCOs from Entity Framework and I'm also generating the Validation classes. In my case I can't really remove one of the calls from SetValidator. In a perfect world the validation would walk the entire object graph but not validate the same instance more than once.
Coordinator
May 20, 2013 at 8:52 AM
Hmm yes, so this does happen in the validator's constructor, not actually at the time of validation, so marking the entity itself as already validated won't actually help. Essentially your validator definitions are doing this:
class Validator() {
  public Validator() {
    new OtherValidator();
  }
  
  public void Validate() { }
}


class OtherValidator() {
  public OtherValidator() {
    new Validator();
  }
}
I'll have a think about how this can be solved, but I would personally explicitly define the validators rather than generating them - this gives you a lot better control of what you're actually validating.