Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Compare (password) attribute

I'd like to create a view model for a new user using the code below. The "User" class contains just the two properties (simplified for now) that I will persist to the database; the view model adds a "compare password" field, which is only used in the view. I'd prefer to have the view model use the "User" class directly, rather than repeating all of the fields defined in "User".

My question is how do I properly reference "User.Password" in the [Compare] attribute for the "ComparePassword" field?

public class User
{
   [Required]
   public string UserName { get; set; }

   [Required]
   [DisplayName("Password")]
   [DataType(DataType.Password)]
   public string Password { get; set; }
}
public class NewUserViewModel
{
    public User User { get; set; }

    [Required]
    [DataType(DataType.Password)]
    [DisplayName("Re-enter Password")]
    [Compare("Password", ErrorMessage="Passwords must match")]
    public string ComparePassword { get; set; }
}

The HTML that gets generated for "Password" and "ComparePassword" is below.

<input class="text-box single-line password" 
  data-val="true" 
  data-val-required="The Password field is required." 
  id="User_Password" 
  name="User.Password" 
  type="password" value="" />

<input class="text-box single-line password" 
  data-val="true" 
  data-val-equalto="Passwords must match" 
  data-val-equalto-other="*.Password"
  data-val-required="The Re-enter Password field is required." 
  id="ComparePassword" 
  name="ComparePassword" 
  type="password" value="" />

The key is how the "data-val-equalto-other" is handled by the Javascript. If I use "Password" or "User_Password" nothing happens - no check is performed. If I use "User.Password" the check is performed but always fails.

I have no real problem doing this directly in jQuery, but would prefer to use the [Compare] attribute if at all possible.

like image 650
Kras Avatar asked Jul 25 '11 15:07

Kras


2 Answers

Just found the answer via StackOverflow and Microsoft Connect:

See:

http://connect.microsoft.com/VisualStudio/feedback/details/665793/jquery-unobtrusive-validate-equalto-fails-with-compare-attribute and JQuery 1.5 breaks Compare Validate (JQuery Validate 1.8)

To summerize, it looks like a bug in the jquery.validate.unobtrusive file that came with MVC3. The workaround is changing the following line in the jquery.validate.unobtrusive file.

element = $(options.form).find(":input[name=" + fullOtherName + "]")[0];

to

element = $(options.form).find(":input[name=" + fullOtherName.replace(".", "\\.") + "]")[0];

On Microsoft Connect, it says MS has fixed it, but i couldnt find the link to the new version. Anyways, this works for me in the meantime. Hope it helps

like image 197
Peter Avatar answered Oct 10 '22 22:10

Peter


I fixed this issue using two fields and comparing on server (via unobtrusive JavaScript):

    [Required(ErrorMessage = @"The new password is required")]
    [StringLength(25, ErrorMessage = @"The new password must be at least {2} characters long", MinimumLength = 4)]
    [DataType(DataType.Password)]
    [Display(Name = @"New Password")]
    public string NewPassword { get; set; }

    [Required(ErrorMessage = @"The confirmation of password is required")]
    [StringLength(25, ErrorMessage = @"The confirmation of new password must be at least {2} characters long", MinimumLength = 4)]
    [DataType(DataType.Password)]
    [Display(Name = @"Confirm New Password")]
    public string ConfirmPassword { get; set; }

Server-side code:

    [HttpPost]
    public ViewResult ChangeUserPassword(ChangePasswordModel model)
    {
        Logger.Debug(LogBuilder.MethodEntry("ChangeUserPassword"));

        if (model == null)
        {
            throw new ArgumentNullException("model");
        }

        if (model.NewPassword != model.ConfirmPassword)
        {
            ModelState.AddModelError("", Messages.ConfirmPasswordError);

            return View(model);
        }

        if (ModelState.IsValid)
        {
            var changePasswordCompleted = false;

            try
            {
                var userName = CurrentPerson.UserDetails.UserName;
                var membershipUser = Membership.GetUser(userName);

                if (membershipUser != null)
                {
                    changePasswordCompleted = membershipUser.ChangePassword(model.OldPassword, model.NewPassword);
                }
            }
            catch (Exception exception)
            {
                changePasswordCompleted = false;

                Logger.Error(LogBuilder.LogMethodError("ChangeUserPassword", exception));
            }

            if (changePasswordCompleted)
            {
                return View("ChangePasswordCompleted");
            }
        }

        ModelState.AddModelError("", Messages.ChangePasswordError);

        return View(model);
    }
like image 44
Julia Savinkova Avatar answered Oct 10 '22 22:10

Julia Savinkova