by Jeff Handley via Jeff Handley on 9/7/2011 6:31:01 AM
For those of you familiar with the ViewModel (or MVVM) pattern, you are likely also familiar with a typical pain point regarding validation: you often need to duplicate your entity validation metadata onto your ViewModel classes. This can lead to burdensome dual maintenance of your validation rules, and it can seem very frustrating that with the server to client metadata propagation that RIA Services offers, your ViewModel classes are left dangling out there for you to manage yourself. In this post, I’ll illustrate a utility I created that allows a ViewModel to assume validation metadata from model classes or properties, eliminating the dual maintenance.
Virtually every ViewModel will have properties that actually represent properties from your model. Let’s use the meeting invitation model from earlier RIA Services Validation posts as an example. My meeting object has a bunch of properties such as Title, Start, End, Location, MinimumAttendees, MaximumAttendees, and Details. It’s easy to imagine a ViewModel that could be used for managing meetings where the UI would have a subset or superset of the meeting properties. For each field on the screen that represents a meeting property, I should be able to indicate which model property is associated with each ViewModel property so that the model validation can be imported automatically. This is where ModelPropertyValidator comes in.
Here’s a subset of the Meeting class with its data annotations in my Web project:
When a ViewModel is going to expose the Start property for a meeting, it would be a nightmare to have to keep all of the validation attributes in sync. To alleviate this, I created an attribute called ModelPropertyValidatorAttribute that acts as a proxy from a ViewModel property to a Model property. Here’s what it looks like to use it:
With a simple attribute on each, the Start and End properties now import all of the validation attributes from their corresponding Model properties on the Meeting type; no more validation duplication! When the property name is the same on the Model and the ViewModel, you can get away with only specifying the model type, but I also have an overload that accepts the model property name in case the property names differ.
Just as there are cases when you want a ViewModel property to import the validation attributes from a model property, there are also times when you want a ViewModel class to import a model’s object-level validation attributes. That’s where ModelObjectValidatorAttribute comes in. Very similarly to the ModelPropertyValidator, you just put the attribute on the ViewModel and specify the corresponding model type.
That’s all there is to it. Now the MeetingEntryViewModel class imports the object-level validation from the Meeting type. You can even specify multiple ModelObjectValidator attributes if you want to import validation attributes from multiple classes.
Here’s how it works:
Yes, I suggested that you make your ViewModel classes derive from ComplexObject. ComplexObject is a really useful class and it exposes a great ValidationErrors collection that any consumer can manipulate, and all updates to that collection generate events from the INotifyDataErrorInfo interface. This works perfectly for this scenario where I want my validation attribute to be able to push multiple validation results onto the target object, despite the fact that the IsValid method is only capable of returning a single error.
Here’s the full code for the ModelValidatorAttribute and the two derived forms.
This was the 10th installment in a blog post series about RIA Services Validation. We’ve learned about the standard validators, how to create different types of custom validators, how the validation attributes get propagated, how to perform common cross-field and cross-entity validation, and now we have a utility for importing model rules into ViewModel classes. Here’s the full series:
The source code for everything shown during the series is available on GitHub.
Original Post: RIA Services Validation: ViewModel Validation with Entity Rules
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.