How do I use IValidatableObject?

Viewed 146987

I understand that IValidatableObject is used to validate an object in a way that lets one compare properties against each other.

I'd still like to have attributes to validate individual properties, but I want to ignore failures on some properties in certain cases.

Am I trying to use it incorrectly in the case below? If not how do I implement this?

public class ValidateMe : IValidatableObject
{
    [Required]
    public bool Enable { get; set; }

    [Range(1, 5)]
    public int Prop1 { get; set; }

    [Range(1, 5)]
    public int Prop2 { get; set; }

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        if (!this.Enable)
        {
            /* Return valid result here.
             * I don't care if Prop1 and Prop2 are out of range
             * if the whole object is not "enabled"
             */
        }
        else
        {
            /* Check if Prop1 and Prop2 meet their range requirements here
             * and return accordingly.
             */ 
        }
    }
}
8 Answers

Implement validation logic using IValidatableObject or property level validation (attributes) than use System.ComponentModel.DataAnnotations.Validator class like this

var validationContext = new ValidationContext(model,, null, null);
var validations = new Collection<ValidationResult>();
Validator.TryValidaObject(model, validationContext, validations, true)

any errors should be present in validations collection (ErrorMessage property should be not empty).

https://docs.microsoft.com/en-us/dotnet/api/system.componentmodel.dataannotations.validator?view=net-6.0

The thing i don't like about iValidate is it seems to only run AFTER all other validation.
Additionally, at least in our site, it would run again during a save attempt. I would suggest you simply create a function and place all your validation code in that. Alternately for websites, you could have your "special" validation in the controller after the model is created. Example:

 public ActionResult Update([DataSourceRequest] DataSourceRequest request, [Bind(Exclude = "Terminal")] Driver driver)
    {

        if (db.Drivers.Where(m => m.IDNumber == driver.IDNumber && m.ID != driver.ID).Any())
        {
            ModelState.AddModelError("Update", string.Format("ID # '{0}' is already in use", driver.IDNumber));
        }
        if (db.Drivers.Where(d => d.CarrierID == driver.CarrierID
                                && d.FirstName.Equals(driver.FirstName, StringComparison.CurrentCultureIgnoreCase)
                                && d.LastName.Equals(driver.LastName, StringComparison.CurrentCultureIgnoreCase)
                                && (driver.ID == 0 || d.ID != driver.ID)).Any())
        {
            ModelState.AddModelError("Update", "Driver already exists for this carrier");
        }

        if (ModelState.IsValid)
        {
            try
            {
Related