views:

209

answers:

2

I have a business model called Customer which has many required properties (via DataAnnotations) and other validation rules.

I have a View which is meant to allow editing of the customer's address fields.

The problem I have is that I want a strongly-typed view but I can't get away with using the Customer type here. Since the view will only be editing address data it won't return any of the other required data the Customer object would need in order to validate.

This suggests that I should use a ViewModel. However, there are many business rules that apply to the address related properties on Customer that I would have to duplicate on the new ViewModel (address lengths, zipcodes, state formatting, etc). They need duplicated because the client-side validation (I'm using xVal) requires that information in order to function.

I feel I've reached a catch-22 scenario. DRY tells me that I should not duplicate my business rules on a ViewModel that my Model already has, but on the other hand I can't use the Model because it will never validate.

What is the best practice in this situation?

The chosen path

The solution I ultimately chose was the ViewModel path. In order to get the validation I needed to work there was simply no other practical way.

However, was was unable to eliminate some rough spots using the ViewModel brought up. I refactored some of my models to use interfaces containing the properties I knew would re-used in the ViewModels. Since the ViewModels could now use the same interfaces as the models it allowed me to do things like this:

 public ActionResult Edit(AddressViewModel address)
 {
      if(!ModelState.IsValid)
          return View();

      var customer = Customer.Load(address.CustomerId);
      UpdateModel<IAddress>(customer);

      // more stuff ....
 }

This saves me the step of using an automapper.

The answer I selected below (by Wyatt Barnett) I felt was good for most cases and I use it on other projects I have, especially useful with Linq-to-Sql.

A: 

From a technical standpoing, your view should only talk to your ViewModel, not the model. So your viewmodel should delegate all the validation to the model. The ViewModel should be adding interaction layer stuff.

Of course this all falls apart in Silverlight, where you typically need some kind of quick validation done at the client side, so all of a sudden you're copying all your validation rules up to the ViewModel anyway. I haven't figured a way around that yet.

Scott Whitlock
Not to sound argumentative, but I think its very important to have validation on the client on a web app. Why cause a round-trip to the server when you can have the user fix their input immediately? Products like xVal exist for this sole purpose.
Sailing Judo
@Sailing Judo - true, but I haven't seen much use of MVVM on strict web applications like ASP.NET. That's usually MVC.
Scott Whitlock
+1  A: 

I ran into the same issue with complex model classes not playing well with simpler views and model binding. I also happened to be using xVal. The trick I fell upon was to use Validation Buddies to cover the DRY angle for basic validation then use AutoMapper to push things back into the full-blown model classes. I can then run a second round of server-side validation to cover the more complex bits that require access to the database and such.

Wyatt Barnett
Interesting read and pretty useful in a general sense. I'm not sure how much this applies to my case... Im not using frozen classes in the sense Graham is, so I don't really need the MetadataType version of the class. Creating a buddy class at this point would just be an extra layer... essentially creating a VM with validation. This might be my only choice, I just don't see it as being "right". I'll keep thinking on this though.
Sailing Judo