Note that there are some explanatory texts on larger screens.

plurals
  1. POASP.NET MVC Architecture : ViewModel by composition, inheritance or duplication?
    primarykey
    data
    text
    <p>I'm using ASP.NET MVC 3 and Entity Framework 4.1 Code First.</p> <p>Let's say I have a <code>User</code> entity :</p> <pre><code>public class User { public int Id { get; set; } public string Name { get; set; } public string Email { get; set; } public string Password { get; set; } } </code></pre> <p>When editing it in my <code>UserController</code> I want to add a <code>PasswordConfirmation</code> field and verify that <code>PasswordConfirmation == Password</code> </p> <h2>1. By composition</h2> <p>My first try was :</p> <pre><code>public class EditUserModel { [Required] public User User { get; set; } [Compare("User.Password", ErrorMessage = "Passwords don't match.")] public string PasswordConfirmation { get; set; } } </code></pre> <p>In this case the client side validation <del>works but</del> (<strong>Edit:</strong> client side validation working was a coincidence.) <strong>doesn't work</strong> and the <strong>server side validation fails</strong> with the following message : <em>Could not find a property named User.Password</em></p> <p><strong>Edit:</strong> I think the best solution, in this case, would be to create a custom <code>CompareAttribute</code></p> <p><strong>Implementing <code>IValidatableObject</code></strong></p> <pre><code>public class EditUserModel : IValidatableObject { [Required] public User User { get; set; } public string PasswordConfirmation { get; set; } public IEnumerable&lt;ValidationResult&gt; Validate(ValidationContext validationContext) { if(this.PasswordConfirmation != this.User.Password) return new[] { new ValidationResult("Passwords don't match", new[] { "PasswordConfirmation " }) }; return new ValidationResult[0]; } } </code></pre> <p>In this case the <strong>server side validation works</strong> but the <strong>client side validation doesn't work</strong> anymore. Implementing <code>IClientValidatable</code> seems a bit too complicated and I prefer not having client side validation in this case.</p> <h2>2. By inheritance</h2> <pre><code>public class EditUserModel : User { [Compare("Password", ErrorMessage = "Passwords don't match.")] public string PasswordConfirmation { get; set; } } </code></pre> <p>When trying to directly save <code>EditUserModel</code> using EF it doesn't work, I get some some error message about the <code>EditUserModel</code> metadata so I'm using <em>AutoMapper</em> to convert from <code>User</code> to <code>EditUserModel</code> and backwards. This solution <strong>works</strong> but it more complex because I have to convert from the model to the view model and backwards.</p> <h2>3. By duplication</h2> <p><em>(Suggested by Malte Clasen)</em></p> <p>The view model would have all the properties of the model plus additional ones. <em>AutoMapper</em> can be used to convert from one to another.</p> <pre><code>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; } } </code></pre> <p>This is the solution I like the least because of code duplication (DRY) </p> <p><strong>Questions</strong></p> <p>What are the pros and cons of inheritance, composition and duplication in this case ?</p> <p>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 ?</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload