MVC3 Object with IValidatableObject - Validate fires multiple times per TryUpdateModel()
I have an object class generated from a T4, with a partial SafeClass to do validation, which looks like this:
public partial class Address : IValidatableObject
This class has a Validate method like so:
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
//ValidationResponse is a custom struct that holds a few properties.
ValidationResponse r = this.IsValidAddress(); //a method that does some checks
if (!r.IsValid)
{
yield return new ValidationResult(r.Message, new string[] { "Address1" });
}
}
In my Controller's HttpPost event, I have the line:
if (!TryUpdateModel(_policy))
return View(_policy);
Note that the Pol开发者_如何学运维icy object contains a Person object, which contains an Address object (pieces of all 3 are rendered in the same view; may be relevant, I don't know).
When TryUpdateModel() executes, the Address's Validate method gets called 3 times. I verified it's not triggering for other addresses on the policy. I have also verified that the Controller's HttpPost method is only being called once. It's the single execution of TryUpdateModel() that fires off 3 Validates.
Has anybody else run into this sort of thing? Any ides what's going on?
I had encoutered similar issue running this code
if (isPoorSpecimen)
{
errors.Add(new ValidationResult("Your are reporting poor specimen condition, please specify what is the reason"
, new string[] { "SpecimenCondition", "QtyOk", "DocumentedOk", "ColdChainOk", "PackagingOK", "IsProcessable" }));
}
It will show the error message 6 times in Html.ValidationSummary() . The solution is to highligt a single control per error.
if (isPoorSpecimen)
{
errors.Add(new ValidationResult("Your are reporting poor specimen condition, please specify what is the reason"
, new string[] { "SpecimenCondition" }));
}
It is called 3 times, because the Address
instance is validated first as a standalone entity, then as a member of a standalone Person
entity, and finally as a member of the Person
entity being a member of the Policy
entity.
I would suggest the following solutions:
1) Remove IValidatableObject
from all the classes but Policy
and validate its members manually:
public class Policy : IValidatableObject
{
public Person PersonInstance { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
// validate Policy...
// then validate members explicitly
var results = PersonInstance.Validate(validationContext);
}
}
public class Person
{
public Address AddressInstance { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
// validate Person...
// then validate members explicitly
var results = AddressInstance.Validate(validationContext);
}
}
public class Address
{
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
// validate Address...
}
}
2) Or add a flag to each class to validate only once, since the instance across the calls is the same:
private bool validated = false;
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (!validated)
{
validated = true;
// do validation
}
}
Hope this helps.
精彩评论