Some weeks ago a friend of mine told me about
System.ComponentModel.DataAnnotations. It’s a relatively new addition to
the framework, mainly Asp.net related (mh, was it Mvc or Asp.net Dynamic
Data? I’m sure he told me, but I can’t remember). Although I’m more
focussed on client side development (WinForms + WPF), what he told me
made me curious enough to spend some time with it in order to
investigate whether the DataAnnotation framework could be reused for
validation in a desktop app.
Background
What I was particulary interested in was whether I could use it in order to implement some sort of declarative validation (for most of the standard cases) on my WPF ViewModels. The usage I wanted to achieve was something similar to the code shown in the next listing.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | |
Here is what I came up with in order to use the DataAnnotation Validators for this
First of all, some basics. I’m going to demonstrate a (very simple)
implementation of the Notification pattern in this post. A detailed
explanation this pattern is a bit out of scope for this post, but
here’re some excellent resources for that:
- The Notification Pattern by Martin Fowler
- Domain centric validation with the Notification Pattern by Jeremy D. Miller
We’re starting with a base class for our Notifications. It’s a simple abstract class containing a message and a Source property. Besides that it contains an implicit conversion to string.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | |
Error is a simple class derived from Notification, which contains no additional code.
1 2 3 4 5 6 | |
I’ve seen some people implementing the Notification pattern with a single Notification class and an enumeration specifying the type of the Notification (Error, Warning, Info, etc.) but I prever using classes for this. I think readability is way better (and shorter) using classes. Decide for yourself:
1 2 3 | |
It’s very rare that you only have to validate one element / property. Mostly we’re dealing with more than one elment beeing validated. Because of that it’s useful to have a container or collection for Notifications. This gives you a nice place for some additional functionality.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | |
While the first properties are pretty obvious, the last method probably needs some explanation. It finds all notifications for a given source name. The source in my implementation is the name of the property on the ViewModel that was validated. Im currently using a little convention here. Properties in WPF views have the same name as the ViewModel properties they’re bound to. This makes it relatively easy to correlate those two things (meaning deciding which Notification belongs to which UIElement). Having set this up, let me walk you through the validator implementation.
A Validator using DataAnnotations
1 2 3 4 5 6 7 8 9 10 11 12 | |
The static constructor of the Validator<TElement> class uses
reflection to find all marked properties of the target type specified
via the generic type argument TElement. It searches for properties
marked at least with one derivate of the System.ComponentModel.DataAnnotations.ValidationAttribute and creates a
PropertyValidator for each match.
1 2 3 4 5 6 7 8 | |
The actual validation happens inside the Validate method. This method simply
uses all known PropertyValidators in order to validate the target
object.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | |
A PropertyValidator does some things internally when it’s created. First it determines the name for
the validated element which should be used in the UI. Since you probably
don’t want the user to see something like “FirstName is required” or
“SelectedCountry is required” I’m using System.ComponentModel.Design.DisplayNameAttribute here which can be used
to specify a UI-friendly name. If no DisplayNameAttribute is specified
on a property the validator uses the property name instead.
1 2 3 4 5 6 7 8 9 | |
After it has determined the UI friendly display name it extracts all DataAnnotations ValidationAttributes from the property.
(Note: GetAttributes is an ExtensionMethod. Same applies to IsMarkedWith and GetAttribute)
1 2 3 4 | |
And here is the rest, which brings the whole thing to life. This code simply extracts the value from
the property, iterates over all known ValidationAttributes and checks
the value with them. When a ValidationAttribute signals that a value is
not valid, an error message is formatted with the UI-friendly name I
talked earlier about and the whole thing is stored as an Error.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | |
Bottom line
It’s pretty easy to combine the existing functionality provided by DataAnnotations with the Notification Pattern. It just took me an hour to get to a working solution which I consider pretty fast and which imho indicates an easy to use framework. As you can imagine the hard part isn’t getting the Notifications out of the model, but rather finding an unrepetative, intuitive way to display them in the UI. In the past I’ve missed several times the pit of success regarding this aspect. However I’m really confident that my current solution is really Dry AND easy to use. In one of the next posts I’m going to show how to combine Attached Behavior, Styles and Templates in order to bring the Notifications described in this post to the applications front door, the UI …