I have been using ASP.NET MVC extensively over the past year, and the more I use it, the more I like it. However, there remain a couple of things that bug me. One is the fact that the built-in validation doesn’t work with repeating forms. The other is the “best practice” of placing Data Annotations on a ViewModel class.
For me, validation rules belong on the business object itself, not on the ViewModel. One of the key benefits of encapsulation is that we reduce code duplication. If we don’t encapsulate the validation rules inside the object, then we are doomed to repeat them once for every presentation layer. Data Annotations in an MVC ViewModel are not available to a WPF UI. Not only does this lead to redundancy, it increases the risk of inconsistencies cropping up between UI.
So no problem, you might think. All we have to do is add the Data Annotations to the Model itself, and then add the Model as a property of the ViewModel.
Okay, let’s try that.
Here is the Model:
And here is the ViewModel:
This looks straightforward enough. But look at what happens when we ask Visual Studio to scaffold the View:
What happened to our “Basic” Model property? It’s not there. The scaffolding only seems to work for simple properties.
Okay, so let’s add the details of the Model to the View. In fact, let’s cheat. We’ll get Visual Studio to scaffold the inner Model for us. First we’ll create a throwaway View. Then we copy the contents of the form and paste it into the View that’s typed to the ViewModel. All we have to do then is change the lambda expressions to point at model.Basic rather than just model:
Problem solved. The View now contains the data we need and also respects our data annotations…
This means we can pass the ViewModel through to a Controller method and pick up the Model we need via the ViewModel’s “Basic” property. There’s only one problem: How do we use the UpdateModel() method when we’re only interested in a property on the object passed to the method, rather than the whole object? Fortunately, Microsoft anticipated the need and there’s an overload on UpdateModel() that allows us to specify a prefix. In this case, not surprisingly, the HTML helpers have inserted the prefix “Basic”:
As you can see, the Model has successfully been bound, so we now have a mechanism for taking advantage of ViewModels without sacrificing encapsulation.
For related information, check out Building Web Applications with ASP.NET MVC from Learning Tree.