Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ASP.NET MVC Architecture : ViewModel by composition, inheritance or duplication?

I'm using ASP.NET MVC 3 and Entity Framework 4.1 Code First.

Let's say I have a User entity :

public class User {     public int Id { get; set; }     public string Name { get; set; }     public string Email { get; set; }     public string Password { get; set; }         } 

When editing it in my UserController I want to add a PasswordConfirmation field and verify that PasswordConfirmation == Password

1. By composition

My first try was :

public class EditUserModel {     [Required]     public User User { get; set; }      [Compare("User.Password", ErrorMessage = "Passwords don't match.")]     public string PasswordConfirmation { get; set; } } 

In this case the client side validation works but (Edit: client side validation working was a coincidence.) doesn't work and the server side validation fails with the following message : Could not find a property named User.Password

Edit: I think the best solution, in this case, would be to create a custom CompareAttribute

Implementing IValidatableObject

public class EditUserModel : IValidatableObject {     [Required]     public User User { get; set; }     public string PasswordConfirmation { get; set; }      public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)     {         if(this.PasswordConfirmation != this.User.Password)             return new[] { new ValidationResult("Passwords don't match", new[] { "PasswordConfirmation " }) };          return new ValidationResult[0];     } } 

In this case the server side validation works but the client side validation doesn't work anymore. Implementing IClientValidatable seems a bit too complicated and I prefer not having client side validation in this case.

2. By inheritance

public class EditUserModel : User {     [Compare("Password", ErrorMessage = "Passwords don't match.")]     public string PasswordConfirmation  { get; set; } } 

When trying to directly save EditUserModel using EF it doesn't work, I get some some error message about the EditUserModel metadata so I'm using AutoMapper to convert from User to EditUserModel and backwards. This solution works but it more complex because I have to convert from the model to the view model and backwards.

3. By duplication

(Suggested by Malte Clasen)

The view model would have all the properties of the model plus additional ones. AutoMapper can be used to convert from one to another.

public class EditUserModel {       public string Name { get; set; }       public string Email { get; set; }       public string Password { get; set; }      [Compare("Password", ErrorMessage = "Passwords don't match.")]        public string ConfirmPassword { get; set; }         } 

This is the solution I like the least because of code duplication (DRY)

Questions

What are the pros and cons of inheritance, composition and duplication in this case ?

Is there a simple way to have both client side and server side validation without having to convert the model to the view model and backwards ?

like image 268
Catalin DICU Avatar asked Aug 05 '11 09:08

Catalin DICU


1 Answers

Having struggled with this question before, I have in various instances gone with all three. In general, most of the opinions I've seen favor duplication in an MVC project, with a ViewModel constructed specifically for each view. In this manner the convention you'd use is something like UserDetailsViewModel and UserCreateViewModel. As you said, at that point AutoMapper or some other auto mapping tool would be used to convert from your domain objects to these flat ViewModels.

While I, too, don't like repeating code, I also don't like polluting my domain objects with validation or other view-specific attributes. Another advantage, though admittedly one almost nobody would ever have to contend with (regardless of what all the pros say), is that you can manipulate your domain objects in some ways without necessarily manipulating your ViewModels. I mention that because it's commonly cited, not because it carries much weight for me.

Lastly, using a truly flat ViewModel makes for cleaner markup. When I've used composition, I've often made errors creating HTML elements with names that are something like User.Address.Street. A flat ViewModel reduces at least my likelihood of doing that (I know, I could always use HtmlHelper routines to create elements, but that's not always feasible).

My recent projects have also pretty much required separate ViewModels these days anyway. They've all been NHibernate-based, and the use of proxies on NHibernate objects makes it not possible to use them directly for views.

Update - here's a good article I've referred to in the past: http://geekswithblogs.net/michelotti/archive/2009/10/25/asp.net-mvc-view-model-patterns.aspx

like image 145
Josh Anderson Avatar answered Sep 22 '22 17:09

Josh Anderson