The source code for this blog post is available for download.
I’ve been using PostSharp for several months at CODY Systems. For the sake of this article, I built a small WPF application that demonstrates our principal use cases. This application is very simple and is split into two assemblies:
- MyCompany.Contracts.dll: a simple assembly with the definition of data contracts such as User, PersonName and Phone. This is an assembly that is meant to be used in WPF client applications, MVC web apps and/or web services (if we were to build any). In addition, this assembly contains all the aspects required for validation and a few other utilities.
- WPFApp.exe: the main executable. It links to the other assembly and contains just one view, its view model and some helper classes.
When you run the application, you will see a dialog that will look like this:
As soon as you change the text of some controls, if the values are invalid and validation rules fail, you will get the following hints being displayed:
The two buttons at the bottom of the dialog show how to trigger validation manually (the 'Validate' button) and how to use my WrapExceptionAspect (the 'Throw Exception' button).
To use IDataErrorInfo/IValidatableObject, or to throw exceptions, this is the question
When you build XAML applications (i.e. WPF, Silverlight or Windows Phone), you are supposed to use the IDataErrorInfo interface to collect errors. These errors are then intercepted by using specific triggers and the collection 'ValidationRules' of the bindings of your view. MVC also respects the interface, although it does so by using the MVC approach to binding and using post-backs.
IValidatableObject is a newer approach in the realm of .Net data validation. It was introduced by MVC 3 and, as far as I know, it is an MVC-only item (by default, at least. You can certainly support it in WPF or Silverlight with some coding).
My main beef with IDataErrorInfo and IValidatableObject is that they expect you not to raise exceptions in property setters which is precisely what the PostSharp Model Patter library does. They treat such situations as something either “bad” or un-common.
In my opinion, property setters that throw exceptions are common and, in many cases, the behavior is a useful feature that makes classes easy to use and understand. The approach follows the same logic of good methods that raise ArgumentNullException(s) or similar exceptions. Good stuff, if you ask me.
For instance, if you were to code a Person class by using IDataErrorInfo guidelines, you would receive no errors assigning Age the value -22 or FirstName a null value. You would not find out about the problem unless you read the Errors property and then acted accordingly.
There are good reasons for designing interfaces that work like this, but in my opinion this is a case where user-interface concerns got mixed up with elements that should follow user-interface-agnostic guidelines.
I understand that sometimes a certain value is invalid only if another property has a specific value (e.g. you cannot have a boolean Juvenile flag being set if the Age is more than 18). Yet, what I found in my experience is that this kind of validation should (more-often-than-not) be delegated to other classes. I call those classes “Validators”.
Complex or cross-property business logic often needs parameters or very configurable rules that might change, depending on the customer. In some systems I worked on, some business rules might be completely eliminated during certain implementations while they could be replaced in their entirety in others Cluttering classes like User, Customer, etc. with those rules usually lead to suboptimal situations (code-wise).
Let me explain by expanding on the Juvenile example above.
The type of software I write relates to law enforcement. If a crime is committed by a Juvenile there are a number of rules that have to be considered. Some rules affect the flow of data (e.g. where are these objects stored? Who can see juveniles and work on them?), others rules determine validity of a Person's object state (e.g. Juvenile can be true if (Age<SysConfiguration.AgeOfAdults) or (Age is null and SysConfiguration.AllowNullAgeForJuveniles)).
The tricky part is that a juvenile is not always a juvenile: what one State considers a juvenile (age of 17) might be considered an adult in another State (e.g. Illinois vs California). If we were to enforce cross-property rules between Juvenile and Age inside the Person class, we'd have to know the configuration of the system inside Person and act accordingly. That, in my opinion, is really not a concern of the Person class.
Person is a class that should never allow a negative Age or a null FirstName. That's about it, and that is what aspects do well. Those rules always make sense, in Person, and belong to the Person “contract”.
The fact a state considers adults at the age of 17 or 18 and the need to check the values of two properties is a problem that originates from ‘where Person’ is used (our system, with a given configuration applied), not what a Person is or should allow for. In addition, it has been advantageous to be able to completely replace certain business logic for some of our customers, so the pluggable 'Validator' played much nicer than embedded (and quasi hard-coded) rules.
Validator classes are then used by view models and server side services (I always double check for such things, as the user of our API might not have access to our C# contract libraries and might need to rely solely on server-side validation).
So, having said this, what I wanted to see is if I can use the PostSharp aspects that ensure 'universal' (i.e. always necessary) object-state integrity, proper formatting of some text (e.g. capitalization of names or other helpful thing of this nature) and, at the same time, build a WPF interface that shows nice errors just like using the IDataErrorInfo interface.
The contracts library is where all the validation rules I choose get defined. The idea is to create a set of classes that are reusable regardless of the user-interface framework you will build clients with. WPF, ASP.Net, ASP MVC... It shouldn't matter. Actually it shouldn't matter if you have a user-interface layer at all. Business contracts should work even without a client and allow you to just write a web service API which is used as-is.
The contracts library in the sample application is very simple. It defines three classes: User, PersonName and Phones. User is defined as follows:
As you can see, there isn't much to it, except an abundance of aspects.
The properties Age and EMail use two aspects that should be obvious to anybody reading the code. That is a very important part of using aspects: they often help making behavior obvious and forego the need to read documentation or dive into code. Range and EmailAddress are part of the Model Pattern Library shipped with PostSharp 3.0. The first will check that the Age is positive and won't allow values bigger than 110. The second will ensure that the email address is properly typed (i.e. firstname.lastname@example.org).
INotifyPropertyChanged No More
At the very top of the class, I used the well-known NotifyPropertyChanged aspect that is probably the most used and most famous aspect that ships with PostSharp. That aspect alone probably eliminated half the code needed to implement the class User. The feature will come handy in WPF and Silverlight apps and it will have no noticeable impact on an MVC app or a web service.
It's also possible to have code that inspects properties and, by looking at what aspects are applied to them, can generate automatic tooltips or verbose documentation.
My Custom Aspects
The Name property is decorated with my very own InstantiateIfNullAspect. That aspect (which I included in this sample) creates instances of the property it is applied to, without the need for repetitive code such as “if (_name==null) _name = new PersonName(); return _name;”. I use this aspect extensively in my contracts library. It allows me to create a new Person and immediately start populating its pieces without thinking about nulls or redundant extra code.
You can see this in the CreateDesignTimeData() method of the view model:
The principle that guides its use, for me, is the following: certain parts of a class (owner) might be defined using other classes, but the owner describes something that would not make sense without the other piece(s). Whenever this rule is met, it probably makes sense to use InstantiateIfNotNullAspect, auto-create inner instances and cut all the boiler-plate code that would be otherwise necessary (especially in the calling code, which is much easier to plague with NullReferenceException(s)).
While the aspect supports interfaces (e.g. you can have a property of type IList and specify that the 'ConcreteType' you want to use to create it is either List, ObservableCollection, etc.), I rarely use it with interfaces. I leave those as properties that are to be filled in, for instance, after fetching data from the server. The fact those properties are null are a reminder that a web-service fetch is necessary. It's up to you to decide if this fits with your needs or not, but I wanted to mention it.
The PersonName class is similar, but I user more aspects, including my StringManipulationAspect. This aspect changes strings by performing one or many common transformations (e.g. remove some type of characters, capitalize text, lower-case it, upper-case it, etc.) that we often need in applications.
Once again, pretty obvious to understand, thanks to aspects.
The Application's View
As you would expect from any decent MVVM application, the view is 99.99% code-free. Specifically, the only code in the main view is the automatically-generated constructor.
The interesting parts are in the XAML code.
The first thing I did was to define a couple of resources that will be needed for my error interception.
The first is a converter ('ErrorMessageConverter') which is capable of getting an exception message and convert it to nicely readable text. This was necessary because the messages coming from the PostSharp validation aspects don't read well (as tool-tips), even if we provided our own error text like I did in the properties First and Last of the class PersonName. Some text-transformations were necessary and the nicer text is what will be displayed by the tool-tips, whenever a validation rule is violated.
The second resource is a style that I want applied to all TextBox(es). This style contains a trigger that binds to the error that was raised (if an error was raised) and uses the previously defined converter 'ErrorMessageConverter'.
With these two resources, I can now continue my XAML coding and have all TextBoxes react to errors by displaying a red box and a tool-tip just adding an ExceptionValidationRule element to its binding:
The purpose of the button 'Validate' is to show how to invoke validation manually. This is something you will need if the form starts without data and you want to guide the user actions. To see it work, enable the commented code in the constructor of the view model, run the application and then click the button.
What happens, when you run the application, is the following: a regular Exception is thrown with the message 'This is the inner exception (…)'. The aspect catches that and wraps it in a GuiException whose message then becomes 'An unexpected error occurred. The error was 'This is the inner exception (…)''.
It's easy to get in situations where some exceptions occur and you don't immediately know what caused them. Often we are given mysterious and miss-leading bug reports that read as 'A 'NullReference crash occurred when I clicked the button', or more nonsense like that.
When I read those reports, I usually get angry for two reasons: the completely useless error report and, right after, the knowledge that I have no immediate pointer to what really happened. The WrapExceptionAspect allows me to wrap exceptions into more meaningful ones, so that I immediately know the area where the problem occurred. Obviously all that happens automatically, since we use aspects.
Server-side, in my web servoces, I tend to create exception types for each area of my API (e.g. FileService, ImageService, SecurityService etc. with the relative FileServiceException, ImageServiceException and SecurityServiceException) and I then wrap the accessible web-methods with the aspect. What happens then is that, instead of getting useless NullReferenceException(s), I get xxxServiceException(s) that wrap the other errors (whatever they are). The exception now immediately points me to the right area so I can focus my attention on the right service or area.
The Model Pattern Library is a great addition to the arsenal provided by PostSharp. While powerful, very easy to use and fall in love with, it's hard to use the validation aspects cleanly, in XAML applications. This article showed a possible solution to the problem so you can plug validation aspects in XAML front-ends without having to duplicate validation logic in IDataErrorInfo of IValidatableObject interfaces.