Home > Enterprise >  How do I properly use DataAnnotations to register users with Identity in .NET 5.0?
How do I properly use DataAnnotations to register users with Identity in .NET 5.0?

Time:09-17

I'm trying to create a registration with Identity in a .NET 5.0 MVC and I'm having problems with my Annotations, especially Compare and Required in my ViewModel. Submitting with an empty email field will reload the page, same with an invalid PW (6 chars, 1 special, 1 num, 1 capital). Submitting with an empty pw field causes a crash in the controller POST route when it tries to use a null pw in CreateAsync().

Any help is appreciated.

Here is my ViewModel

using System.ComponentModel.DataAnnotations;

namespace Test.ViewModels
{
    public class RegisterViewModel
    {
        [Required]                      // doesn't seem to work
        [EmailAddress]                  // this works
        [Display(Name = "Email")]       // works
        public string Email { get; set; }

        [Required]                     // doesn't work
        [DataType(DataType.Password)]  // doesn't seem to do anything
        [Display(Name = "Password")]   // works
        public string Password { get; set; }

        [Required]                          // doesn't work
        [DataType(DataType.Password)]       // doesn't seem to do anything
        [Display(Name = "Confirm password")] // works
        [Compare(nameof(Password), ErrorMessage = "The password and confirmation password do not match.")] // doesn't work
//      [Compare("Password")]  also doesn't work
        public string ConfirmPassword { get; set; }
    }
}

here is my View

@using Test.ViewModels
@model RegisterViewModel

<h2>Register a new user</h2>

@using (Html.BeginForm("Register", "Account"))
{
    @Html.LabelFor(user => user.Email)
    @Html.EditorFor(user => user.Email)

    @Html.LabelFor(user => user.Password)
    @Html.PasswordFor(user => user.Password)

    @Html.LabelFor(user => user.ConfirmPassword)
    @Html.PasswordFor(user => user.ConfirmPassword)

    <input type="submit" value="Register" />
}

Here is the controller post action

        [HttpPost]
        public async Task<ActionResult> Register (RegisterViewModel model)
        {
            var user = new ApplicationUser { UserName = model.Email };
            IdentityResult result = await _userManager.CreateAsync(user, model.Password);
            if (result.Succeeded)
            {
                return RedirectToAction("Index");
            }
            else
            {
                return View();
            }
        }

I've tried these other hits for SO answers on this and I haven't found a solution in them, maybe because they are 7-10 years old.

Using DataAnnotations to compare two model properties

Email address validation using ASP.NET MVC data type attributes - this one helped solve a problem with [EmailAddress], I was using the wrong HTML Helper so it wasn't validating the input.

CodePudding user response:

The solution was in a link posted by @mohammad-mobasher, and this link was very helpful.

What I was missing was using @Html.ValidationSummary(false) in my view and wrapping the code in my POST route with if (ModelState.IsValid){}. @Html.ValidationSummary(false) checks for validation on the ViewModel properties and will add an unordered list with any violations to the register page if the the form is submitted and the model state is not valid.

The change to the controller looks like this:

[HttpPost]
public async Task<ActionResult> Register(RegisterViewModel model)
{
  if (ModelState.IsValid) // this is new
  {
    ApplicationUser user = new ApplicationUser { UserName = model.Email };
    IdentityResult result = await _userManager.CreateAsync(user, model.Password);
    if (result.Succeeded)
    {
      return RedirectToAction("Index");
    }
  }
  return View(model);
}

and the view:

@using Test.ViewModels
@model RegisterViewModel

<h2>Register a new user</h2>
<hr />
@using (Html.BeginForm("Register", "Account", FormMethod.Post))
{
  @Html.LabelFor(user => user.Email)
  @Html.TextBoxFor(user => user.Email)   
  <!-- changed back to TextBoxFor, now the Validation method works for this -->


  @Html.LabelFor(user => user.Password)
  @Html.PasswordFor(user => user.Password)

  @Html.LabelFor(user => user.ConfirmPassword)
  @Html.PasswordFor(user => user.ConfirmPassword)

  <input type="submit" value="Register" />
}

<!-- added this -->
@Html.ValidationSummary(false) 
  • Related