locked
Edit columns of AspNetUsers table in Entity Framework MVC RRS feed

  • Question

  • User1753363434 posted

    Hi everyone.

    I'm doing a ASP.NET MVC project, and at some point i want to able the user to edit his profile, most concretly the UserName field(AspNetUsers table)

    I've made some research, and all i've found was how to add new colums to the table and i don't want that, i just want to edit the UserName field as by default it gets the email value. So can someone help me, please?

    Stay safe.

    Wednesday, February 24, 2021 1:28 AM

Answers

  • User1686398519 posted

    Hi stewiefre, 

    According to your needs, I wrote an example, you can refer to it

    1. You need to add a method(Edit) to modify the username.
    2. You can modify the example I provided according to your needs.
    3. I modified it in the "Identity" template project, so the code for the unmodified part was not provided.

    EditViewModel

        public class EditViewModel
        {
            [Required]
            [Display(Name = "UserName")]
            public string UserName { get; set; }
            [Required]
            [EmailAddress]
            [Display(Name = "Email")]
            public string Email { get; set; }
        }

    RegisterViewModel

        public class RegisterViewModel
        {
            [Required]
            [Display(Name = "UserName")]
            public string UserName { get; set; }
            [Required]
            [EmailAddress]
            [Display(Name = "Email")]
            public string Email { get; set; }
    
            [Required]
            [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
            [DataType(DataType.Password)]
            [Display(Name = "Password")]
            public string Password { get; set; }
    
            [DataType(DataType.Password)]
            [Display(Name = "Confirm password")]
            [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
            public string ConfirmPassword { get; set; }
        }

    _LoginPartial.cshtml

        using (Html.BeginForm("LogOff", "Account", FormMethod.Post, new { id = "logoutForm", @class = "navbar-right" }))
        {
            @Html.AntiForgeryToken()
            var userName=String.IsNullOrEmpty(User.GetClaimValue("UserName"))?User.Identity.GetUserName(): User.GetClaimValue("UserName");        
            <ul class="nav navbar-nav navbar-right">
                <li class="dropdown">
                    <a id="dLabel" href="#" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
                        Hello @userName !
                    </a>
                    <ul class="dropdown-menu" aria-labelledby="dLabel">
                        <li>
                            @Html.ActionLink("Manage", "Index", "Manage", routeValues: null, htmlAttributes: new { title = "Manage" })
                        </li>
                        <li>
                            @Html.ActionLink("Modify Personal Information", "Edit", "Account", routeValues: null, htmlAttributes: new { title = "Edit" })
                        </li>
                    </ul>
                </li>
                <li><a href="javascript:document.getElementById('logoutForm').submit()">Log off</a></li>
            </ul>
        }

    Edit

    <h2>Edit</h2>
    @model WebApplication3.Models.EditViewModel
    @using (Html.BeginForm("Edit", "Account", FormMethod.Post))
    {
    @ViewBag.Message
    @Html.ValidationSummary("", new { @class = "text-danger" })
    <div class="form-group">
        @Html.DisplayNameFor(m => m.UserName)
        @Html.TextBoxFor(m => m.UserName, new { @class = "form-control" })
    </div>
    <div class="form-group">
        @Html.DisplayNameFor(m => m.Email)
        @Html.TextBoxFor(m => m.Email, new { @class = "form-control" })
    </div>
    <button type="submit">Edit</button>
    }

    AccountController.cs

            [HttpPost]
            [AllowAnonymous]
            [ValidateAntiForgeryToken]
            public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
            {
                if (!ModelState.IsValid)
                {
                    return View(model);
                }
                // This doesn't count login failures towards account lockout
                // To enable password failures to trigger account lockout, change to shouldLockout: true
                var user = await UserManager.FindByEmailAsync(model.Email);
                var result = await SignInManager.PasswordSignInAsync(user.UserName, model.Password, model.RememberMe, shouldLockout: false);
                switch (result)
                {
                    case SignInStatus.Success:
                        return RedirectToLocal(returnUrl);
                    case SignInStatus.LockedOut:
                        return View("Lockout");
                    case SignInStatus.RequiresVerification:
                        return RedirectToAction("SendCode", new { ReturnUrl = returnUrl, RememberMe = model.RememberMe });
                    case SignInStatus.Failure:
                    default:
                        ModelState.AddModelError("", "Invalid login attempt.");
                        return View(model);
                }
            }
            [HttpGet]
            public async Task<ActionResult> Edit()
            {
                var user = await UserManager.FindByIdAsync(User.Identity.GetUserId());
                var model = new EditViewModel
                {
                    UserName = user.UserName,
                    Email = user.Email
                };
                return View(model);
            }
            [HttpPost]
            public async Task<ActionResult> Edit(EditViewModel model)
            {
                var user = await UserManager.FindByIdAsync(User.Identity.GetUserId());
                user.UserName = model.UserName;
                user.Email = model.Email;
                var t = await UserManager.UpdateAsync(user);
                if (t.Succeeded)
                {
                    User.AddUpdateClaim("UserName", user.UserName);
                    ViewBag.Message = "succcess";
                }
                else
                {
                    ViewBag.Message ="fail";
                }
                return View(model);
            }
            [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);
                    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 https://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);
            }

    AddOrUpdateClaim.cs

        public static class Extensions
        {
            public static void AddUpdateClaim(this IPrincipal currentPrincipal, string key, string value)
            {
                var identity = currentPrincipal.Identity as ClaimsIdentity;
                if (identity == null)
                    return;
                var existingClaim = identity.FindFirst(key);
                if (existingClaim != null)
                    identity.RemoveClaim(existingClaim);
                identity.AddClaim(new Claim(key, value));
                var authenticationManager = HttpContext.Current.GetOwinContext().Authentication;
                authenticationManager.AuthenticationResponseGrant = new AuthenticationResponseGrant(new ClaimsPrincipal(identity), new AuthenticationProperties() { IsPersistent = true });
            }
            public static string GetClaimValue(this IPrincipal currentPrincipal, string key)
            {
                var identity = currentPrincipal.Identity as ClaimsIdentity;
                if (identity == null)
                    return null;
                var claim = identity.Claims.FirstOrDefault(c => c.Type == key);
                return claim==null?null: claim.Value;
            }
        }

    Here is the result. 

    Best Regards,

    YihuiSun

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Thursday, February 25, 2021 8:41 AM

All replies

  • User1686398519 posted

    Hi stewiefre, 

    I want to confirm with you, did you use Identity?

    stewiefre

    just want to edit the UserName field as by default it gets the email value. So can someone help me, please?

    Do you mean that the UserName value you get from the database is the email address?

    If you use the Identity template project, you will find that the user name you created is the email address when registering the project.You can do not assign an email address to UserName when creating a user.

    var user = new ApplicationUser { UserName = model.Email, Email = model.Email };
    var result = await UserManager.CreateAsync(user, model.Password);

    You can use UserManager.Update() to modify the UserName value of a user in the database.

    Best Regards,

    YihuiSun

    Wednesday, February 24, 2021 10:25 AM
  • User1753363434 posted

    Yes, i've used Identity template project, and so i would like the user to change that value in the runtime. 

    What changes i've to make in the controller and in the view? In the view can i use the login template?

    Wednesday, February 24, 2021 11:15 AM
  • User1753363434 posted

    I think that at the beggining i wasn't 100% explicit in what i really want to do.

    I want the user to be able to edit/update the table in a view, like the register form with a button to save the data user has inputed, but in this case a "edit form" with a button to update that info

    Wednesday, February 24, 2021 11:27 AM
  • User1686398519 posted

    Hi stewiefre, 

    According to your needs, I wrote an example, you can refer to it

    1. You need to add a method(Edit) to modify the username.
    2. You can modify the example I provided according to your needs.
    3. I modified it in the "Identity" template project, so the code for the unmodified part was not provided.

    EditViewModel

        public class EditViewModel
        {
            [Required]
            [Display(Name = "UserName")]
            public string UserName { get; set; }
            [Required]
            [EmailAddress]
            [Display(Name = "Email")]
            public string Email { get; set; }
        }

    RegisterViewModel

        public class RegisterViewModel
        {
            [Required]
            [Display(Name = "UserName")]
            public string UserName { get; set; }
            [Required]
            [EmailAddress]
            [Display(Name = "Email")]
            public string Email { get; set; }
    
            [Required]
            [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
            [DataType(DataType.Password)]
            [Display(Name = "Password")]
            public string Password { get; set; }
    
            [DataType(DataType.Password)]
            [Display(Name = "Confirm password")]
            [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
            public string ConfirmPassword { get; set; }
        }

    _LoginPartial.cshtml

        using (Html.BeginForm("LogOff", "Account", FormMethod.Post, new { id = "logoutForm", @class = "navbar-right" }))
        {
            @Html.AntiForgeryToken()
            var userName=String.IsNullOrEmpty(User.GetClaimValue("UserName"))?User.Identity.GetUserName(): User.GetClaimValue("UserName");        
            <ul class="nav navbar-nav navbar-right">
                <li class="dropdown">
                    <a id="dLabel" href="#" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
                        Hello @userName !
                    </a>
                    <ul class="dropdown-menu" aria-labelledby="dLabel">
                        <li>
                            @Html.ActionLink("Manage", "Index", "Manage", routeValues: null, htmlAttributes: new { title = "Manage" })
                        </li>
                        <li>
                            @Html.ActionLink("Modify Personal Information", "Edit", "Account", routeValues: null, htmlAttributes: new { title = "Edit" })
                        </li>
                    </ul>
                </li>
                <li><a href="javascript:document.getElementById('logoutForm').submit()">Log off</a></li>
            </ul>
        }

    Edit

    <h2>Edit</h2>
    @model WebApplication3.Models.EditViewModel
    @using (Html.BeginForm("Edit", "Account", FormMethod.Post))
    {
    @ViewBag.Message
    @Html.ValidationSummary("", new { @class = "text-danger" })
    <div class="form-group">
        @Html.DisplayNameFor(m => m.UserName)
        @Html.TextBoxFor(m => m.UserName, new { @class = "form-control" })
    </div>
    <div class="form-group">
        @Html.DisplayNameFor(m => m.Email)
        @Html.TextBoxFor(m => m.Email, new { @class = "form-control" })
    </div>
    <button type="submit">Edit</button>
    }

    AccountController.cs

            [HttpPost]
            [AllowAnonymous]
            [ValidateAntiForgeryToken]
            public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
            {
                if (!ModelState.IsValid)
                {
                    return View(model);
                }
                // This doesn't count login failures towards account lockout
                // To enable password failures to trigger account lockout, change to shouldLockout: true
                var user = await UserManager.FindByEmailAsync(model.Email);
                var result = await SignInManager.PasswordSignInAsync(user.UserName, model.Password, model.RememberMe, shouldLockout: false);
                switch (result)
                {
                    case SignInStatus.Success:
                        return RedirectToLocal(returnUrl);
                    case SignInStatus.LockedOut:
                        return View("Lockout");
                    case SignInStatus.RequiresVerification:
                        return RedirectToAction("SendCode", new { ReturnUrl = returnUrl, RememberMe = model.RememberMe });
                    case SignInStatus.Failure:
                    default:
                        ModelState.AddModelError("", "Invalid login attempt.");
                        return View(model);
                }
            }
            [HttpGet]
            public async Task<ActionResult> Edit()
            {
                var user = await UserManager.FindByIdAsync(User.Identity.GetUserId());
                var model = new EditViewModel
                {
                    UserName = user.UserName,
                    Email = user.Email
                };
                return View(model);
            }
            [HttpPost]
            public async Task<ActionResult> Edit(EditViewModel model)
            {
                var user = await UserManager.FindByIdAsync(User.Identity.GetUserId());
                user.UserName = model.UserName;
                user.Email = model.Email;
                var t = await UserManager.UpdateAsync(user);
                if (t.Succeeded)
                {
                    User.AddUpdateClaim("UserName", user.UserName);
                    ViewBag.Message = "succcess";
                }
                else
                {
                    ViewBag.Message ="fail";
                }
                return View(model);
            }
            [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);
                    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 https://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);
            }

    AddOrUpdateClaim.cs

        public static class Extensions
        {
            public static void AddUpdateClaim(this IPrincipal currentPrincipal, string key, string value)
            {
                var identity = currentPrincipal.Identity as ClaimsIdentity;
                if (identity == null)
                    return;
                var existingClaim = identity.FindFirst(key);
                if (existingClaim != null)
                    identity.RemoveClaim(existingClaim);
                identity.AddClaim(new Claim(key, value));
                var authenticationManager = HttpContext.Current.GetOwinContext().Authentication;
                authenticationManager.AuthenticationResponseGrant = new AuthenticationResponseGrant(new ClaimsPrincipal(identity), new AuthenticationProperties() { IsPersistent = true });
            }
            public static string GetClaimValue(this IPrincipal currentPrincipal, string key)
            {
                var identity = currentPrincipal.Identity as ClaimsIdentity;
                if (identity == null)
                    return null;
                var claim = identity.Claims.FirstOrDefault(c => c.Type == key);
                return claim==null?null: claim.Value;
            }
        }

    Here is the result. 

    Best Regards,

    YihuiSun

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Thursday, February 25, 2021 8:41 AM
  • User1753363434 posted

    It just missed editing register view, including the UserName field, by default it doesn't appear in register view.

    Thank you, it was exactly what i needed.

    Cheers.

    Thursday, February 25, 2021 12:12 PM
  • User1753363434 posted
    var userName=String.IsNullOrEmpty(User.GetClaimValue("UserName"))?User.Identity.GetUserName(): User.GetClaimValue("UserName");

    It gives me error in User.GetClaimValue. I've created Extensions class inside Models folder. Is that right?
    Thursday, February 25, 2021 12:53 PM
  • User1686398519 posted

    Hi stewiefre, 

    stewiefre

    I've created Extensions class inside Models folder

    If you create it under the "Models" folder, you need to import the namespace where the Extensions class is located(on the _LoginPartial.cshtml view): xxx..Models.

    @using WebApplication3.Models

    But I recommend that you don't put it under the "Models" folder, generally speaking, this folder contains the classes that define the objects and the logic for interacting with the database or data items.

    I put the Extensions class in the root directory of the project, so I didn't import the namespace on the view.

    It just missed editing register view, including the UserName field, by default it doesn't appear in register view.

    I'm sorry I missed the code on the Register.cshtml view. The newly added code is as follows:

    @using (Html.BeginForm("Register", "Account", FormMethod.Post, new { @class = "form-horizontal", role = "form" }))
    {
    ... ... <div class="form-group"> @Html.LabelFor(m => m.UserName, new { @class = "col-md-2 control-label" }) <div class="col-md-10"> @Html.TextBoxFor(m => m.UserName, new { @class = "form-control" }) </div> </div>
    ... ... }

    Best Regards,

    YihuiSun

    Friday, February 26, 2021 1:39 AM
  • User1753363434 posted

    That's it, thank u! :)

    Cheers.

    Friday, February 26, 2021 2:26 AM