Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to call IValidatableObject Validate(ValdationContext) in MVC3 or include in ModelUpdate? [duplicate]

It seems that when MVC validates a Model that it runs through the DataAnnotation attributes (like required, or range) first and if any of those fail it skips running the Validate method on my IValidatableObject model.

Is there a way to have MVC go ahead and run that method even if the other validation fails?

like image 616
Mr Bell Avatar asked Jun 21 '11 20:06

Mr Bell


People also ask

What method do you need to provide when implementing the IValidatableObject interface?

Open model and implement the IValidatableObject interface. You can get this pop-up by pressing Ctrl+. (dot). It implements a validatable interface automatically in Visual Studio.

What does ModelState IsValid validate?

ModelState.IsValid property is an inbuilt property of ASP.Net MVC which verifies two things: 1. Whether the Form values are bound to the Model. 2. All the validations specified inside Model class using Data annotations have been passed.

What is validation context?

ValidationContext(Object) Initializes a new instance of the ValidationContext class using the specified object instance. ValidationContext(Object, IDictionary<Object,Object>) Initializes a new instance of the ValidationContext class using the specified object and an optional property bag.


1 Answers

You can manually call Validate() by passing in a new instance of ValidationContext, like so:

[HttpPost]
public ActionResult Create(Model model) {
    if (!ModelState.IsValid) {
        var errors = model.Validate(new ValidationContext(model, null, null));
        foreach (var error in errors)                                 
            foreach (var memberName in error.MemberNames)
                ModelState.AddModelError(memberName, error.ErrorMessage);

        return View(post);
    }
}

A caveat of this approach is that in instances where there are no property-level (DataAnnotation) errors, the validation will be run twice. To avoid that, you could add a property to your model, say a boolean Validated, which you set to true in your Validate() method once it runs and then check before manually calling the method in your controller.

So in your controller:

if (!ModelState.IsValid) {
    if (!model.Validated) {
        var validationResults = model.Validate(new ValidationContext(model, null, null));
        foreach (var error in validationResults)
            foreach (var memberName in error.MemberNames)
                ModelState.AddModelError(memberName, error.ErrorMessage);
    }

    return View(post);
}

And in your model:

public bool Validated { get; set; }

public IEnumerable<ValidationResult> Validate(ValidationContext validationContext) {
    // perform validation

    Validated = true;
}
like image 62
gram Avatar answered Sep 22 '22 16:09

gram