Tuesday, 30 November 2010

Encapsulating boolean return types.

.Net 4 introduced some changes to the way DataAnnotations ValidationAttributes work. Pre .NET 4 you would check the validity of a property on a class by attributing it with a ValidationAttribute (custom or otherwise) and then calling the IsValid():bool method. This is straight forward and logical. However; this approach leaves a bit to be desired. If IsValid() returns false, what exactly is it that invalidates my property? It would be better if validation was approached differently, and this is what DataAnnotations in .NET 4 does.

In .NET 4 the use of IsValid():bool is discouraged. In fact, if you create a new custom validation attribute (extending ValidationAttribute) and do not override IsValid() before you call it, it will throw a NotImplementedException with the message "IsValid(object value) has not been implemented by this class. The preferred entry point is GetValidationResult() and classes should override IsValid(object value, ValidationContext context)."

As you can see, you're encouraged to override an overload of IsValid(). If you look closer you'll see that the overload does not return true/false, but instead returns a ValidationResult which is a wee bit more informative. Also, the overload is protected - so you can't call it externally. Instead you call the GetValidationResult() method to see what the result of validation is.

Why is this better than just returning true or false? It's because a ValidationResult carries information about why validation failed.

You might now think that this is a bit overkill for scenarios in which validation is successful. In this case, more often than not, all you care about is knowing that validation has passed and that you can carry on. The ValidationResult class facilitates this by applying the Null Object Pattern and encapsulating a static property called ValidationResult.Success against which you can compare the ValidationResult instance returned to you by GetValidationResult() (ValidationResult.Success always returns null, because a null validation result signifies successful validation).

This approach doesn't just apply to validation scenarios. Ayende Rahien talks about why and how he uses this approach here. If you have a method that returns true/false and there is no more relevant information available, fine. However, if the true/false answer masks other information then the approach of encapsulating the answer in a class is better.

Monday, 29 November 2010

Go on. Get NuGet.

I spent most of yesterday afternoon (Sunday!) messing about with FluentNHibernate, trying to compile the source to .NET4, NHibernate 3 Beta, and Castle Windsor 2.5.

What. A. Waste. Of. Time.

Sometimes I just don't think. Somebody out there would probably have done this already, right? The answer to that question is yes. But it wasn't until I happened upon the hornget project that bells started ringing: "Hmmmm.... that's awfully similar to NuGet, isn't it?" Yes, it is.

Suffice to say that 10 minutes after this realisation I had FluentNHibernate running in my solution, with NHibernate 3 Beta and Castle Windsor 2.5.

So if you haven't already, go on and get NuGet.

Thursday, 25 November 2010

Testing routes with MVC3 RC1 and .NET 4

Yesterday I found myself needing to test some MVC routes. I wanted to avoid setting up all the mocking infrastructure needed to do so, and decided to use the MVCContrib project to ease the work. However, I am building an MVC 3 RC1 app on .NET 4 - and MVCContrib targets .NET 3.5 and MVC 2, so I quickly ran into trouble.

I tried converting the solution to .NET 4.0 - but it was too time consuming to do so. Instead I ripped out the pieces I needed, i.e. the route testing extension methods, and built a new assembly targeting the right versions of the framework. And I replaced RhinoMocks with Moq.

Using the Mvc.TestHelper assembly you can easily test routes with syntax like this:
"~/".ShouldMapTo<HomeController>(x => x.Index());
"~/Account/".ShouldMapTo<AccountController>(x => x.Register(null));

Note: I take zero credit for this work. All the source code is taken directly from the MVCContrib project.

I have made the source available on BitBucket so that you can test your MVC 3 routes. The project uses NUnit and Moq for testing.