by Jeff Handley via Jeff Handley on 10/17/2009 12:40:34 AM
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:
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:
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).
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:
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:
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.
Original Post: Validating Objects and Properties with Validator
The content of the postings is owned by the respective author. Silverlight Feeds is not responsible for the contents of the postings. This site is automatically generated and cannot be reviewed for abusive content. If you find abusive content on Silverlight Feeds, please contact us. Designated trademarks and brands are the property of their respective owners. All rights reserved.