Manual Validation with Data Annotations

Wednesday, June 29, 2011

Several people have asked me about using data annotations for validation outside of a UI framework, like ASP.NET MVC or Silverlight. The System.ComponentModel.DataAnnotations assembly contains everything you need to execute validation logic in the annotations. Specifically, there is a static Validator class to execute the validation rules. For example, let's say you have the following class in a console mode application:

public class Recipe
    public string Name { get; set; } 

You could validate the recipe with the following code:

var recipe = new Recipe();
var context = new ValidationContext(recipe, serviceProvider: null, items: null);
var results = new List<ValidationResult>();

var isValid = Validator.TryValidateObject(recipe, context, results);

if (!isValid)
    foreach (var validationResult in results)

Result: "The Name field is required".

You can construct the ValidationContext class without a service provider or items collection, as shown in the above code, as they are optional for the built-in validation attributes. The Validator also executes any custom attributes you have defined, and for custom attributes you might find the serviceProvider useful as a service locator, while the items parameter is a dictionary of extra data to pass along. The Validator also works with self validating objects that implement IValidatableObject.

public class Recipe : IValidatableObject 
    public string Name { get; set; }

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
        // ...

Like everything framework related, the Validator tries to provide an API that will work in a number of validation scenarios. I recommend you bend it to your will and build something that makes it easy to use inside your specific design and architecture. A class like the following would be a step towards hiding some complexity.

public class DataAnnotationsValidator
    public bool TryValidate(object @object, out ICollection<ValidationResult> results)
        var context = new ValidationContext(@object, serviceProvider: null, items: null);
        results = new List<ValidationResult>();
        return Validator.TryValidateObject(
            @object, context, results, 
            validateAllProperties: true

gravatar Johan Thursday, June 30, 2011
Sweet! Very useful!
gravatar Prashant Brall Thursday, June 30, 2011
Very nice, short and simple :)
Zukki Friday, July 1, 2011
thanks Scott, your Master Pages: Tips, Tricks, and Traps article was a big help for me, your blog is on my favorites now!
gravatar rtpHarry Friday, July 1, 2011
Scott, correct me if I'm wrong but shouldn't this line: var isValid = Validator.TryValidateObject(recipe, context, results); have an out keyword on the results parameter?
gravatar rtpHarry Friday, July 1, 2011
I will correct myself :) No, it doesn't have an out.
gravatar Thanigainathan Monday, July 4, 2011

Thanks for sharing this usefuk info
gravatar Yann Friday, July 15, 2011
Worth mentioning that the Validator class from the Data Annotations namespace doesn't validate your object recursively but only top properties data attributes.
If some of your properties are complex types for which you've set data annotations attributes, validation will not run.

It can quite easily be done using reflection with recursion though.
gravatar Scott Monday, July 18, 2011
If the name property had some metadata, like [DisplayName("FullName")], you'd still get the error message "The Name field is required." Any idea how to get validation to pay attention to System.ComponentModel metadata in this scenario?
gravatar scott Monday, July 18, 2011
@scott: Use [Display(Name="...")] instead. That one should work.
EHA Tuesday, August 2, 2011
Have you tested you code yourself.. ? It doesn't work..
gravatar scott Tuesday, August 2, 2011
@EHA: I tested the code.
gravatar James William Friday, August 5, 2011
A nice way to validate. Great article
Comments are closed.

My Pluralsight Courses

K.Scott Allen OdeToCode by K. Scott Allen
What JavaScript Developers Should Know About ECMAScript 2015
The Podcast!