views:

328

answers:

5

Hey guys

Here is the lay of the land. Like most people I have my domain object and I have my view models. I love the idea of using view models, as it allows for models to be created specifically for a given view context, without needing to alter my business objects.

The problem I have is with type level validation defined on my domain object and getting those rules to the client. In this case lets say I am using data annotations to describe the validation rules, when I move the data from the domain object to the view model, the view model no longer knows what validation it should get the interface to perform (because the validation is defined back on the domain object).

With MVC 2 you can get it to automatically perform client/server side validation, based on the validation rules of the current object. But because the validation rules are defined on the domain object and not the view model, I would have to duplicate the validation rules on the view model to get this to work.

How do others deal with this type of issue? My thinking is that besides mapping the data from the domain object to the view model, we also need to map across the validation rules, but I haven't really seen others talking about this issue... Brad Wilson has recently talked about this issue at length but hasn't really addressed the duplication of rules on the domain object and on the view models... what are your thoughts?

Cheers Anthony

+2  A: 

This may not be appropriate, but what if you just moved your validation rules/annotations from your Models to your ViewModels? In a few of the projects I've been on, we've chosen to prevent the View from accessing anything but information exposed through its corresponding ViewModel. Since all data interaction would be performed through the ViewModel, there wouldn't be a need to have validation on your Model objects.

The counter to this argument is that you could easily duplicate certain validation rules, since different ViewModels might be interfacing with the same Models. In this case, it might make sense to simply declare your Model as a property exposed on your ViewModel. For postbacks, they could accept a Model as their parameter, allowing the ModelBinder infrastructure to handle the request. In this case, if ModelState.IsValid is false, you could just reassign the property to your ViewModel before redisplaying the View.

I would recommend moving your annotations to your ViewModels. It makes sense since a lot of Views are a) the result of composition of several models or b) a subset of model data.

Adrian Anttila
A: 

Probably we shouldn't use view models at all? And define validation rules on model layer entities..

Gopher
+3  A: 

The DataAnnotation attributes are about validating input and giving UI feedback to the end user. That's really their only intended use. I use different validation strategies for UI objects and business objects, so the DA validation attributes only end up on models being shown to the user.

Brad Wilson
Hey thanks for the reply. So you use the DataAnnotation and MVC's ability to use this on your view model, to provide rich experience to the user and use a completely different strategy for your business objects. I am assuming if validation fails at the business objects level your have a way of piping the messages back? Also how do you go with keeping the validation rule in sync? Lastly, what sort of validation framework do you use for the business objects? I think this topic would be a great blog post if you had time... congrats on RC.
anthonyv
It depends on what the message is, but most of the time, no, I'm not piping messages back to the user. The only time you end up having to pipe business messages back to the user is when it's the only place that can actually validate something (f.e., database uniqueness).
Brad Wilson
Thanks for the feedback. I would really encourage you to do a blog post on this topic as I know I would really benefit from it and I am sure others would as well. You could lay out same examples where your VM's are being validated as well as your business objects and how that all comes together. Thanks again.
anthonyv
A: 

I've been considering this as well for a while now. I totally understand Brad's reply. However, let's assume I want to use another validation framework that is suitable for annotating both domain entities and view models.

The only solution I can come up with on paper that still works with attributes would be to create another attribute that "points" to a domain entity's property that you are mirroring in your view model. Here's an example:

// In UI as a view model.
public class UserRegistration {
  [ValidationDependency<Person>(x => x.FirstName)]
  public string FirstName { get; set; }

  [ValidationDependency<Person>(x => x.LastName)]
  public string LastName { get; set; }

  [ValidationDependency<Membership>(x => x.Username)]
  public string Username { get; set; }

  [ValidationDependency<Membership>(x => x.Password)]
  public string Password { get; set; }
}

A framework like xVal could possibly be extended to handle this new attribute and run the validation attributes on the dependency class' property, but with your view model's property value. I just haven't had time to flesh this out more.

Any thoughts?

ventaur
At least with the proposed solution, you'll run into issues with not being able to put Lambda statements in attributes. It is an unfortunate restriction.
Chris
I liked the idea but Chris pointed out that this mightn't work... I think there needs to be a way to 'port' across not just the validation definitions but the meta data in general... but I'm not sure how this would fit in in seamless way...
anthonyv
Oooh. Good points. This is why I should do a quick test before posting some times. Of course, another option would be to forgo attribute annotations for validation and use a rules engine that allows you to assign a rule (by reference to an instance or by name from a list) to one or more properties. Perhaps the assignment could be done via attributes.[ValidateWithRule("Required"), ValidateWithRule("MaxNameLength")]public string FirstName { get; set; }
ventaur
I keep thinking more on this, because it has bugged me for a long time. Keeping with the annotations approach, you could "link up" your validation between domain model and view model similar to how an IoC container or AutoMapper setup associations between classes. This could be part of your bootstrapping code. ValidationMapper.Sync<UserRegistraion>(x => x.FirstName).To<Person>(p => p.FirstName);
ventaur
@ventaur: Assuming you keep the property names the same (which you probably will if the validation is truly mappable), then you could have single class level attribute that specified the class to map to. Then the convention would be that anything with the same name gets mapped. With MVC 2 the validation model is pluggable, so you should be able to try this.
Chris
+1  A: 

It turns out that AutoMapper may be able to do this for us automagically, which is the best case scenario.

AutoMapper-users: Transfer validation attributes to the viewmodel?
http://groups.google.com/group/automapper-users/browse_thread/thread/efa1d551e498311c/db4e7f6c93a77302?lnk=gst&amp;q=validation#db4e7f6c93a77302

I haven't got around to trying out the proposed solutions there, but intend to shortly.

(Cross posted this on my (dupe) question as well).

Martin Aatmaa