ASP.NET Dynamic Data introduced the System.ComponentModel.DataAnnotations namespace in .NET 3.5 SP1. The namespace contained a bunch of attributes for applying validation rules to objects and their properties. With the “Alexandria” project (which morphed into .NET RIA Services plus some Silverlight/SDK/Toolkit additions), we were exposing your server-side entities up to your Silverlight client. In doing this, we wanted to preserve your DataAnnotations attributes on the client, which of course meant that we needed a Silverlight version of this assembly. (See Also: Sharing Source with Silverlight).

As our team was creating this Silverlight assembly, we found that we needed a utility to easily validate an object and/or its properties. This utility would be used by the Silverlight DataGrid and DataForm controls when objects are edited or added. We also hit some scenarios that led to new requirements for the validation attributes. The result was some fairly significant additions and changes that ended up being included in the Silverlight 3 SDK. Here are some of the crucial differences between the .NET 3.5 SP1 version of DataAnnotations, and the Silverlight 3 version:

Validator is a static class providing utility methods for validating properties and objects.

bool ValidationAttribute.IsValid(object) is internal in Silverlight, but public and virtual in .NET 3.5 SP1 (Desktop framework).

ValidationResult ValidationAttribute.IsValid(object, ValidationContext) was added to replace IsValid(object) as the method attributes will override.

ValidationAttribute.GetValidationResult serves as the public entry point instead of IsValid(object).

ValidationResult represents an error produced as a result of validation (note that the static ValidationResult.Success is used to represent successful validation).

ValidationContext represents the context under which validation is being performed, providing access to the object instance, its type, and other state/context.

In .NET 3.5 SP1, the only way to ask a validation attribute if it was valid for a given value was through the IsValid(object) API. When performing validation for a property attribute, the value of the property is supplied as the value to validate, giving no contextual information about the rest of the object’s properties. This severely limits what can be done with the validation attributes. With .NET RIA Services, we wanted to ensure that more context is always provided to the attributes, so we created the ValidationContext class to represent provide this information. ValidationContext has some useful properties:

ObjectInstance is the object being validated, so that property-level validators can access the containing object.

ObjectType is the type of the object being validated.

DisplayName is the display name of the property or object being validated, respecting the [Display] attribute if utilized.

MemberName is the property name or type name of the property or object being validated.

Items is a property bag that can be used to provide additional state/context for the validation.

ValidationContext also implements IServiceProvider, so that services (such as a repository) can be provided to the attributes being validated.

It’s important to note that for cross-field validation, relying on the ObjectInstance comes with a caveat. It’s possible that the end user has entered a value for a property that could not be set—for instance specifying “ABC” for a numeric field. In cases like that, asking the instance for that numeric property will of course not give you the “ABC” value that the user has entered, thus the object’s other properties are in an indeterminate state. But even so, we’ve found that it’s extremely valuable to provide this object instance to the validation attributes.

The new Validator class relies heavily on this ValidationContext when calling its validation methods. These methods are meant to be the interface that frameworks and applications use to perform validation, rather than forcing everyone to iterate over the attributes and validate them. Validator actually comes with some low-level building blocks as well as higher-level methods. For each of the following, the Try method is a bool that indicates whether or not validation was successful, with a collection of ValidationResults being populated along the way. The method without the Try prefix is a void, throwing a ValidationException upon the first validation failure (or completing without exception when successful).

[Try]ValidateValue takes any value and a list of validation attributes, and validates each attribute using the value and the supplied ValidationContext.

[Try]ValidateProperty takes a value and a ValidationContext that specifies the ObjectInstance and MemberName to validate.

[Try]ValidateObject takes an object instance and a ValidationContext where the ObjectInstance matches the instance provided, and validates all property-level and object-level validation attributes.

You’ll notice that each of these methods requires that you provide a ValidationContext, and this often trips people up because constructing a ValidationContext requires a few parameters.

Here are the constructor parameters for ValidationContext:

object instance – The object instance being validated – such as your Customer entity. Note that this is not the property value when you are validating a property.

IServiceProvider serviceProvider – This is an optional source to use for the ValidationContext IServiceProvider implementation. If you have services that you need to expose to your validation attributes, you can provide a service provider to the validation context, and then the attributes can retrieve the services through the ValidationContext’s implementation of IServiceProvider. Essentially, ValidationContext just serves as a wrapper around your provider.

IDictionary<object, object> items – This is just a state bag that you can optionally provide to give your validation attributes any other state information that you so desire. The dictionary is available through the Items property on ValidationContext. Note that the dictionary is immutable during validation, so your validation attributes cannot change the dictionary values such that they would be available to subsequent validation attributes, as validation order is indeterminate.

If you don’t have a service provider or state bag that you are using, you can just use null for both of those parameters. We explicitly did not provide an overloaded constructor to omit these parameters, because we want to encourage the use of the parameters. We expect that application developers will create static CreateValidationContext methods, simplifying the construction of the ValidationContext. (In fact, that’s what RIA Services does).

The great thing about all of this plumbing that we’ve done is that it actually makes your job for validating properties and objects very straight-forward. Once you create a validation context and call into the Validator, here’s what happens:

You’ll notice that GetValidationResult is public but not virtual. That’s because it does work that wraps around the IsValid method to ensure that there’s an error message produced from invalid validation results. So when you’re creating a ValidationAttribute class, you will override the IsValid method, giving you access to the ValidationContext every time your attribute is validated.

Now, there’s one major topic missing from this longwinded story. All of this new stuff was created and released with Silverlight 3, but what about the desktop framework? The good news is that all of this is provided for the desktop framework in 3 different ways:

Between the two frameworks, there are still some casual differences, where we couldn’t make breaking changes to the desktop framework, but we wanted Silverlight to adopt the newer API more aggressively. But regardless of which framework you’re working against, the flow will be the same. This ensures that you can create your validation attribute classes as shared code that compiles against both the desktop framework and Silverlight.

There was also one very noteworthy addition made only to the desktop version of DataAnnotations. We introduced an interface for IValidatableObject. This interface has a single method for Validate that accepts the ValidationContext (with the ObjectInstance set) and returns an IEnumerable<ValidationResult>. This method allows you to have very dynamic validation on your entities. This approach could also be useful for entities have lots of cross-field validation that cannot easily be represented with attributes.

When validating an object, the following process is applied in Validator.ValidateObject:

Validate property-level attributes

If any validators are invalid, abort validation returning the failure(s)

Validate the object-level attributes

If any validators are invalid, abort validation returning the failure(s)

If on the desktop framework and the object implements IValidatableObject, then call its Validate method and return any failure(s)

If you are developing a framework or application that needs to validate business objects and their properties, using the Validator class is strongly recommended, as it does a lot of the grunt work for you. If you have any questions or problems regarding how you can best implement your validation, please drop me a line.

Your Comments.

I have a problem with custom validator and the validation summary. The validator summary does't shows the custom validator results.

I build a Silverlight3 Business Application with RIA toolkit 2009 (VS2008 prof). The server project has an Entity Model, and a Domain Service for this entity model. I add a new validation attribute in a shared file

In the code I set the DataForm CurrentItem to a new instance of MyEntity

Page1.xaml.cs:

MyForm.CurrentItem = new MyEntity();

When I run the application the validator set the ValidationResult, but the DataForm ValidationSummary is empty.I checked with breakpoints, that the silverlight goes into my validator and set the result to invalid state. If I take a default validator

If the attribute-based model suits your project, I would have no hesitation in using this assembly on the project, for either the desktop framework or Silverlight. With .NET RIA Services, it is important that the model can be validated on the server and within Silverlight to produce the same results, so parity between the frameworks was essential.

Originally I was quite excited to see that this was released outside of .NET 4. Unfortunately after several hours of struggling with it I am strongly considering going back to write my own. I thought I'd explain some of the troubles I had with it.

First, the last parameter on TryValidate, validateAllProperties is incredibly unintuitive. Why would I *not* want to validate all properties? What does it mean to only validate some? What's the default? Of course I know all the answers to these thanks to reflector. The answers were shocking. The default is to NOT validate all properties and the only properties validated are ones that have a required attribute. I'm not sure what drove this design decision but I can tell you as an outsider attempting to consume the api this was not intuitive and cost me a lot of time and frustration.

I would suggest including a parameter called validateOnlyRequired if you require this behavior and default *that* to false.

Next, it appears that there is no out of the box way to do recursive validation. In order to get this I had to make a custom ValidationAttribute to "opt-in" to nested validation by just performing validation. It would be nice if this was built in or was at least an option on the Validator. Maybe there is already but I didn't see it anywhere.

Finally, since I'd rather not have this extra attribute everywhere I was hoping I could modify the behavior of the Validator class. Unfortunately, it's static and therefore completely locked up. I don't see a good reason for making this static. If you want a static helper method that will new up the default implementation and use it, fine. But please do not put all of the behavior in a static class.

I understand that these are early releases and some of these things may have already changed. Hopefully it's not too late to consider some of these issues. I'd love to be able to use this Validator and not have to reinvent the wheel.

Feel free to contact me at aaronjensen at gmail if you'd like me to clarify anything. I'd be happy to help in any way I can.

Also, when I've implemented IValidatableObject, I found the behaviour of Validator.TryValidateObject doesn't fit with my needs. (It could just be my code...). I don't seem to get the Validate method called until all of the attribute-based validations pass. This seems to fit with the behavior that you describe for Validator.ValidateObject, but I'd like to have my IValidatableObject's Validate method called even when some of the attribute-based validations have failed. (I'm mapping Validator.TryValidateObject into an IDataErrorInfo implementation for a WPF desktop app)...

Anyhow, if you want to email me at nigelwarmstrong at hotmail dot com if you want my sample code that would be fine.

I'm trying to use the Validator class in conjuction with the Entity Framework in 3.5 SP1. Currently we have Meta-Data classes to specify validation attributes for our entity classes via the MetadataTypeAttribute.

It seems that the Validator class does not support this behaviour. Is there any quick workaround to this?

Please can you hep with a problem I am facing. I am not able to change the layout of the validation summary. I want to move the validation summary from the bottom of the control(gridview) and move it to the top of the gridview control. I have a silverlight application and using RIA services.

I am currently in the process of making one such frame application which does need business objects and I think this Validator class is going to make my work somewhat easy. Thanks for showing this in detail.

I'm trying to extend this similar to how I can do it in MVC by using ModelValidatorProviders and ModelValidators, but the two approaches seem to be really different. Although MVC also uses DataAnnotations, they don't seem to be using Validator. (I'm wondering if the reasons is because Validator doesn't provide the necessary extension points).

I also noticed there's no IValidatableObject in Silverlight which was another possible extension point.

Do you know if I could extend RIA to plug in my own validation mechanism?

However, I too think there are some really odd design decisions here. I'm especially miffed about the early validation bow-out if attribute validation fails.

Validation is about letting the user know what's wrong in the application and it's much more user-friendly to show ALL user errors instead of having the user fix one thing and then be presented with another set of errors - that's just evil UI design :-) I vote for having an option to have validation go through all of the validation and provide all the validation errors at least optionally...

I'm creating an application using Silverlight and RIA Services. For the validation on the client-side, I'm using Validator. I've a "Customer" entity, which contains an "Address" entity and I want to fill all the data and validate both entities before saving them.

How can I do? If I validate the "Customer" entity, the "Address" entity, which is one of its attributes, is not validated. Did I forget something?