Removing Data Validation from MVC Controllers


You require custom data validation that cannot be accomplished via the built-in data annotation validation attributes – or – your data validation requires access to multiple properties in your model. Let’s explore how to leverage the IValidatableObject.

When Validation Attributions won’t do the trick

Many times the easy answer is to place the validation inside of your controller. However, I’m a strong believer of placing data validation outside of your controllers and within your data model. This is commonly accomplished by adding data annotation above the properties, such as the [Required] attribute. Another common way is to create your own validation attributes.

This example will use a third way and that is to implement the IValidatableObject interface. This interface defines a Validate function that must be implemented and because it is inside of your data model it has access to all properties within your model.

Implementing the IValidatableObject

To demonstrate the IValidatableObject I’ve created a model that contains three properties: Quantity, MaxQuantity (nullable), and FixedQuantity. The validation rules are, if FixedQuantity is true, MaxQuantity should be null.

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;

namespace RedirectWithModel.Models
public class ValidationModel : IValidatableObject
public int Quantity { get; set; }
public int? MaxQuantity { get; set; }
public bool FixedQuantity { get; set; }

public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
if (FixedQuantity && MaxQuantity.HasValue)
yield return new ValidationResult(“A max quantity should not be specified when FixedQuantity is true”);

Inside the Validate function, when FixedQuantity is true and MaxQuantity contains any value, a new ValidationResult is returned with an error message letting the user know what is wrong.

The following validation rule will be applied when the ModelState.IsValid is called typically from a controller or a global filter.

About the author

By Jamie

My Books