37

There's already an answered question about the same subject but as it's from '09 I consider it outdated.

How to properly implement "Confirm Password" in ASP.NET MVC 3?

I'm seeing a lot of options on the Web, most of them using the CompareAttribute in the model like this one

The problem is that definitely ConfirmPassword shound't be in the model as it shouldn't be persisted.

As the whole unobstrusive client validation from MVC 3 rely on the model and I don't feel like putting a ConfirmPassword property on my model, what should I do?

Should I inject a custom client validation function? If so.. How?

Andre Pena
  • 56,650
  • 48
  • 196
  • 243
  • 4
    Not all the types (or type members) that are in *Model* must be persisted. What about your server validation? – oleksii Jul 23 '11 at 16:48
  • 1
    Not only ConfirmPassword, but also Password should not be persisted. Darin Dimitrov's solution with a ViewModel is correct except for the note about AutoMapper. You should always salt and secure hash password prior to persisting it. – Juraj Suchár Aug 15 '12 at 09:58
  • Darin never indicated that he would persist the plaintext password, he just said that he would map the viewmodel to a domain model, and pass that to a repository. I would argue that the details of hashing a password more correctly belongs with the persistence code than in the presentation code (Why should my MVC controllers have to know the details of a secure hash?). – David Hay Feb 20 '14 at 18:46

2 Answers2

97

As the whole unobstrusive client validation from MVC 3 rely on the model and I don't feel like putting a ConfirmPassword property on my model, what should I do?

A completely agree with you. That's why you should use view models. Then on your view model (a class specifically designed for the requirements of the given view) you could use the [Compare] attribute:

public class RegisterViewModel
{
    [Required]
    public string Username { get; set; }

    [Required]
    public string Password { get; set; }

    [Compare("Password", ErrorMessage = "Confirm password doesn't match, Type again !")]
    public string ConfirmPassword { get; set; }
}

and then have your controller action take this view model

[HttpPost]
public ActionResult Register(RegisterViewModel model)
{
    if (!ModelState.IsValid)
    {
        return View(model);
    }

    // TODO: Map the view model to a domain model and pass to a repository
    // Personally I use and like AutoMapper very much (http://automapper.codeplex.com)

    return RedirectToAction("Success");
}
Shaiju T
  • 6,201
  • 20
  • 104
  • 196
Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
  • I don't have a `Compare` attribute available... what am I missing? – jocull Feb 23 '12 at 16:45
  • @jocull, erm, ASP.NET MVC 3? If you are using an older version you won't have this attribute. – Darin Dimitrov Feb 23 '12 at 16:46
  • It's definitely MVC 3... am I missing an included assembly? – jocull Feb 23 '12 at 16:47
  • 2
    @jocull, read the [documentation](http://msdn.microsoft.com/en-us/library/system.web.mvc.compareattribute.aspx). Assembly: `System.Web.Mvc.dll`. Namespace: `System.Web.Mvc`. – Darin Dimitrov Feb 23 '12 at 16:48
  • Oh crap, I forgot for this project that the "core" models are in a separate assembly... that is probably the problem. Thanks. – jocull Feb 23 '12 at 16:49
  • 3
    In newer C# its better use `[Compare(nameof(Password), ...]` instead of hardcoding `Password` property name. – Mariusz Jamro Jan 13 '17 at 11:50
  • Does that mean both Password and ConfirmPassword are being sent to the server? Do we really need both if the validation can be done client-side? – Mladen B. Apr 09 '19 at 07:56
3

Take a look at the default VS2010 template for a MVC3 app.

It contains a RegisterModel (a 'ViewModel') that contains the Password and ConfirmPassword properties. The validation is set on the ConfirmPassword.

So the answer is that the Models in MVC don't have to be (usually aren't) the same as your business Models.

H H
  • 263,252
  • 30
  • 330
  • 514