1

I am admittedly still very green in the realm of C# and MVC5, but learning more everyday, so your patience with my lack of knowledge is greatly appreciated.

I have read everything I could find and can still not get the following to work. Truthfully I tried to get the cleaner .Trial(password) to work, but realized that was probably over my head. That would be preferred, but at least getting this ugly version to work would be fantastic. The "trial" method does not get called from what I can tell, but can not check as I get an error when I try to debug it with a breakpoint.

.

I have the following in my AccountViewModels.cs

[Validator(typeof(RegisterViewModelValidator))]
public class RegisterViewModel {
    [Display(Name = "User name")]
    public string UserName { get; set; }

    [Display(Name = "Email")]
    public string Email { get; set; }

    [DataType(DataType.Password)]
    [Display(Name = "Password")]
    public string Password { get; set; }

    [DataType(DataType.Password)]
    [Display(Name = "Confirm password")]
    public string ConfirmPassword { get; set; }


}




public class RegisterViewModelValidator : AbstractValidator<RegisterViewModel> {
    public RegisterViewModelValidator() {

        RuleFor(x => x.UserName)
            .NotEmpty()
                .WithMessage("Username is required");

        RuleFor(x => x.Email)
            .NotNull()
                .WithMessage("E-mail is required")
            .EmailAddress()
                .WithMessage("E-mail is invalid");

        RuleFor(x => x.Password)
           .Must(password => Trial(password))
                .WithMessage("Password must triggered");

        RuleFor(x => x.ConfirmPassword)
            .Equal(x => x.Password)
                .WithMessage("Confimation odes not match");

    }

    private bool Trial(string value) {
        if (string.IsNullOrEmpty(value)) {
            return false;
        } else {
            return true;
        }
    }
}

and the following in my Global.asax

 FluentValidation.Mvc.FluentValidationModelValidatorProvider.Configure();

and this is in my view

<div id="regesterFormContainer" class="col-md-4">


            @using (Html.BeginForm("Register", "Account", FormMethod.Post, new { id = "regesterForm", autocomplete = "off" })) {

                @Html.AntiForgeryToken()


                @Html.ValidationMessageFor(m => m.UserName, string.Empty, new { @class = "error-class" })
                @Html.TextBoxFor(m => m.UserName, new { id = "regesterUserNam", placeholder = "Username", @class = "registerFormInputs", title = "4-20 characters with letters, numbers, - and _" })


                @Html.ValidationMessageFor(m => m.Email, string.Empty, new { @class = "error-class" })
                @Html.TextBoxFor(m => m.Email, new { id = "regesterEhMell", placeholder = "E-Mail Address", @class = "registerFormInputs", title = "Must be a valid e-mail address." })


                @Html.ValidationMessageFor(m => m.Password, string.Empty, new { @class = "error-class" })
                @Html.PasswordFor(m => m.Password, new { id = "regesterPess", placeholder = "Password", @class = "registerFormInputs", title = "5-20 characters. An Uppercase letter, lowercase letter and a number are required." })

                @Html.ValidationMessageFor(m => m.ConfirmPassword, string.Empty, new { @class = "error-class" })
                @Html.PasswordFor(m => m.ConfirmPassword, new { id = "regesterConPess", placeholder = "Confirm Password", @class = "registerFormInputs", title = "Must match password above." })


                <div class="registerSubmitFrame">
                    <input type="submit" class="registerSubmit" value="Register">
                </div>
                <p><a id="showExtReg">Show external registration options</a></p>


            }



        </div>

The applicable controller chunk

 [HttpPost]
        [AllowAnonymous]
        [ValidateAntiForgeryToken]
        public async Task<ActionResult> Register(RegisterViewModel model) {
            if (ModelState.IsValid) {
                var user = new ApplicationUser { UserName = model.UserName, Email = model.Email };
                var result = await UserManager.CreateAsync(user, model.Password);


                var validator = new RegisterViewModelValidator();
                validator.Validate(model);  // viewmodel should be passed into the controller method on POST via model binding.



                if (result.Succeeded) {
                    await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);

                    // For more information on how to enable account confirmation and password reset please visit http://go.microsoft.com/fwlink/?LinkID=320771
                    // Send an email with this link
                    // string code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
                    // var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = user.Id, code = code }, protocol: Request.Url.Scheme);
                    // await UserManager.SendEmailAsync(user.Id, "Confirm your account", "Please confirm your account by clicking <a href=\"" + callbackUrl + "\">here</a>");

                    return RedirectToAction("Index", "Home");
                }
                AddErrors(result);
            }

            // If we got this far, something failed, redisplay form
            return View(model);
        }

I appreciate your time and patience

FocusTorn
  • 33
  • 7
  • Edited it to remove the other validation portions for the password, leaving only the "must" – FocusTorn Nov 13 '15 at 18:49
  • Can you post the error that is getting thrown? – Ron Saylor Nov 13 '15 at 18:53
  • It just works and it hit the breakpoint when I test on my local machine. – CodeNotFound Nov 13 '15 at 19:34
  • "get an error when I try to debug it with a breakpoint." what error? Post your controller code.. – felickz Nov 13 '15 at 19:59
  • AbstractValidator.cs not found You need to find the AbstractValidator.cs to view the source for the current call stack frame. And it does hit the breakpoint, but can not step into the code. One step into and I get that. WHen you say that is just works and hit the break point, do you mean the trial method fired for you, and gave your the validation result? – FocusTorn Nov 14 '15 at 00:03

2 Answers2

0

Try:

RuleFor(x => x.Password)
    .NotEmpty()
         .WithMessage("Password in required")
    .Length(6, 100)
        .WithMessage("Password not long enough")
    .Must(Trial)
        .WithMessage("Password must triggered");

private bool Trial(RegisterViewModel viewModel, string value) {
    if (string.IsNullOrEmpty(value)) {
        return false;
    } else {
        return true;
    }
}
Ron Saylor
  • 381
  • 6
  • 19
0

You may have an issue binding your view model in the controller handling the POST. Show us your controller code.

You can put this in your controller to verify this:

var validator = new RegisterViewModelValidator();
validator.Validate(viewModel);  // viewmodel should be passed into the controller method on POST via model binding.

EDIT: To Clarify,

The following validators are supported on the client:

NotNull/NotEmpty
Matches (regex)
InclusiveBetween (range)
CreditCard
Email
EqualTo (cross-property equality comparison)
Length

In OP's case he should be using "NotEmpty" which would take the place of this "Must" logic:

   private bool Trial(string value) {
        if (string.IsNullOrEmpty(value)) {
            return false;
        } else {
            return true;
        }
    }

AND it would run both on the jquery unobtrusive Client and Server MVC model validations.

felickz
  • 4,292
  • 3
  • 33
  • 37
  • Added the controller piece above, but I had thought that the Fluent Validation happens pre-post receipt in the controller, ion the client-side. I added the piece you said to and still does not work. – FocusTorn Nov 13 '15 at 21:44
  • @FocusTorn Must "predicate" does not run on client side.. [Note that FluentValidation will also work with ASP.NET MVC's client-side validation, but not all rules are supported](https://github.com/JeremySkinner/FluentValidation/wiki/h.-MVC) You added my code first line in the Action and you still don't hit the breakpoint in your Trial method? To Test, get rid of your AntiCSRF validation, it might be haywire. What is your ModelState.IsValid returning true/false? – felickz Nov 14 '15 at 01:31
  • Fantastic! I was unaware that the must ran post post... I thought it was like the .NotNull().WithMessage("E-mail is required") that happen client side. Ok so it does what it was designed to do. Should I post a new question for: how do I make one that runs client side like the .NotNull() ? – FocusTorn Nov 14 '15 at 03:09
  • Also, why var validator instead of RegisterViewModelValidator validator = new? – FocusTorn Nov 14 '15 at 03:10
  • @FocusTorn The native "NotEmpty" validator would essentially be your same "Trial" logic... and will run client side. I updated my answer. – felickz Nov 16 '15 at 19:28
  • @FocusTorn var is new to C# 3, lets you write less verbose code. [See](http://stackoverflow.com/questions/41479/use-of-var-keyword-in-c-sharp) – felickz Nov 16 '15 at 19:30
  • @felickz- good stuffabout var. The dinky lil code for the Must is only becuase I knew exactly what that logic would do. The real motivator behind the must was orriginally to have 3 different regex to be used. and give a different error each. has cap letter, has lower case letter has integer. – FocusTorn Nov 16 '15 at 21:35
  • @FocusTorn `Matches (regex)` works on client side, make sure the regex you write in C# is also supported in javascript [see limitations on javascript regex here](http://www.regular-expressions.info/javascript.html) ... particularly painful is ignore case, you have to look for lowercase and capitol letter explicitly. – felickz Nov 17 '15 at 18:31
  • Right, I got the Regex to work using a custom PropertyValidator and the matches, but I want to do a client-side validation using multiple Regex matches or multiple customs to get error messages that are specific instead of a 3part error. I. E. Password has no number..... Password has no symbol, instead of them both being in the same one. So the user knows exactly what the issue is. Is that even something fluent can do, or do I need to go j Query for client-side and fluent for server-side? – FocusTorn Nov 17 '15 at 19:24
  • @FocusTorn I use a server side validator for that exact use case. I made the message very detailed and all encompassing if any of the tests in my Must() validation fail. I am not sure if you can apply multiple validators of same type on same field... worth a try! – felickz Nov 19 '15 at 21:04