How to Edit ASP.NET Core Identity User

How to Edit ASP.NET Core Identity User

In this article, I will discuss How to Edit ASP.NET Core Identity User. Please read our previous article discussing How to Retrieve and Display All Registered Users from the ASP.NET Core Identity Database.

Edit ASP.NET Core Identity User:

Editing a user in ASP.NET Core Identity involves creating a form that allows users to submit their updated information, handling this data in a controller action, validating the updated information, and then applying the changes to the database using Entity Framework Core. We need to follow the following steps:

  • Retrieve the User: First, we need to retrieve the user we want to edit. This is usually done through the UserManager class. To do this, we need to use a method like FindByIdAsync or FindByEmailAsync, depending on the requirement, i.e., whether we want to fetch the User by ID and Email.
  • Update User Properties: Once we have the user object, we need to modify its properties. For example, we can change the user’s email, name, or other property in the IdentityUser class or the custom class that extends the IdentityUser class.
  • Validate the Changes: It’s important to validate the changes before saving them into the database. ASP.NET Core Identity has built-in validation, but we can also implement custom validation logic.
  • Update the User: After making and validating the changes, we need to save these changes to the database. This is done using the UserManager class UpdateAsync method.
  • Check the Result: The UpdateAsync method returns an IdentityResult object. We need to check this object to see if the update was successful and handle errors, if any.

Let us proceed and see how we can implement this in our project.

Edit Button on List Users View

We created the following ListUsers view in our previous article, where we provided a button for editing the user information.

Edit Button on List Users View

When we click the Edit button against any user in the ListUsers view, we want to redirect the user to the URL: /Administration/EditUser/UserId. So, please modify the ListUsers.cshtml view to add the Edit link to be redirected to the EditUser action method of the Administration controller by taking the UserId as a parameter.

@model IEnumerable<ApplicationUser>

@{
    ViewBag.Title = "All Users";
}

<h1>All Users</h1>

@if (Model.Any())
{
    <a asp-action="Register" asp-controller="Account"
       class="btn btn-primary mb-3" style="width:auto">
        Add New User
    </a>

    foreach (var user in Model)
    {
        <div class="card mb-3">
            <div class="card-header">
                User Id : @user.Id
            </div>
            <div class="card-body">
                <h5 class="card-title">@user.UserName</h5>
            </div>
            <div class="card-footer">
                <a asp-action="EditUser" asp-controller="Administration"
                   asp-route-UserId="@user.Id" class="btn btn-primary">Edit</a>
                <a href="#" class="btn btn-danger">Delete</a>
            </div>
        </div>
    }
}
else
{
    <div class="card">
        <div class="card-header">
            No Users Added Yet
        </div>
    </div>
}
EditUserViewModel Class:

Create a class file named EditUserViewModel.cs and then copy and paste the following code. This class is going to hold the user data needed by the Edit User View:

using System.ComponentModel.DataAnnotations;

namespace ASPNETCoreIdentityDemo.Models
{
    public class EditUserViewModel
    {
        //To avoid NullReferenceExceptions at runtime,
        //initialise Claims and Roles with a new list in the constructor.
        public EditUserViewModel()
        {
            Claims = new List<string>();
            Roles = new List<string>();
        }

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

        [Required]
        [Display(Name = "User Name")]
        public string UserName { get; set; }

        [Required]
        [EmailAddress]
        public string Email { get; set; }

        [Display(Name = "First Name")]
        public string? FirstName { get; set; }

        [Display(Name = "Last Name")]
        public string? LastName { get; set; }

        public List<string> Claims { get; set; }

        public IList<string> Roles { get; set; }
    }
}
EditUser HttpGet Action Method

We need two actions in our Administration Controller: one to display the form (GET request) and another to process the form data (POST request). So, add the following EditUser Get Action method to the Administration Controller. This method will fetch all the user details and pass them to the EditUser view.

[HttpGet]
public async Task<IActionResult> EditUser(string UserId)
{
    //First Fetch the User Details by UserId
    var user = await _userManager.FindByIdAsync(UserId);

    //Check if User Exists in the Database
    if (user == null)
    {
        ViewBag.ErrorMessage = $"User with Id = {UserId} cannot be found";
        return View("NotFound");
    }

    // GetClaimsAsync retunrs the list of user Claims
    var userClaims = await _userManager.GetClaimsAsync(user);

    // GetRolesAsync returns the list of user Roles
    var userRoles = await _userManager.GetRolesAsync(user);

    //Store all the information in the EditUserViewModel instance
    var model = new EditUserViewModel
    {
        Id = user.Id,
        Email = user.Email,
        UserName = user.UserName,
        FirstName = user.FirstName,
        LastName = user.LastName,
        Claims = userClaims.Select(c => c.Value).ToList(),
        Roles = userRoles
    };

    //Pass the Model to the View
    return View(model);
} 

We use the following three ASP.NET Core Identity methods in this example.

FindByIdAsync Method:
  • This method finds a user based on their unique identifier, typically a string representing the user’s ID in the database. The method returns a Task<TUser>, which, when awaited, gives you the user entity if found or null if no user is found with that ID. Example: var user = await _userManager.FindByIdAsync(UserId);
GetClaimsAsync Method:
  • This method retrieves all claims associated with a specific user. Claims are a way of adding additional data about the user, such as their roles or permissions. The AspNetUserClaims table stores all the claims. Currently, we have not stored any claims. The method returns a Task<IList<Claim>>, which, when awaited, returns a list of claims (System.Security.Claims.Claim) associated with the user. Example: var userClaims = await _userManager.GetClaimsAsync(user);
GetRolesAsync Method:
  • This method retrieves all the roles associated with a specific user. The method returns a Task<IList<string>>, which, when awaited, returns a list of role names (string) that the user belongs to. Example: var userRoles = await _userManager.GetRolesAsync(user);
Edit User View

The look and feel of the EditUser view is shown below. Here, we have three sections. The first section is for updating the user’s basic information. The second section shows the list of roles assigned to the user and a link to Manage the roles. The third section shows the list of claims assigned to the user and a link to manage the claims. Currently, we have not added any claims, so the claim section is empty.

Edit User View

So, create a view named EditUser.cshtml within the Views/Administration directory and copy and paste the following code. The model for this view is EditUserViewModel.

@model EditUserViewModel

@{
    ViewBag.Title = "Edit User";
}

<h1>Edit User</h1>

<form method="post" class="mt-3">
    <input type="hidden" asp-for="Id" />
    <div class="form-group row">
        <label asp-for="Id" class="col-sm-2 col-form-label"></label>
        <div class="col-sm-10">
            <input asp-for="Id" disabled class="form-control">
        </div>
    </div>
    <div class="form-group row">
        <label asp-for="Email" class="col-sm-2 col-form-label"></label>
        <div class="col-sm-10">
            <input asp-for="Email" class="form-control">
            <span asp-validation-for="Email" class="text-danger"></span>
        </div>
    </div>
    <div class="form-group row">
        <label asp-for="UserName" class="col-sm-2 col-form-label"></label>
        <div class="col-sm-10">
            <input asp-for="UserName" class="form-control">
            <span asp-validation-for="UserName" class="text-danger"></span>
        </div>
    </div>
    <div class="form-group row">
        <label asp-for="FirstName" class="col-sm-2 col-form-label"></label>
        <div class="col-sm-10">
            <input asp-for="FirstName" class="form-control">
        </div>
    </div>

    <div class="form-group row">
        <label asp-for="LastName" class="col-sm-2 col-form-label"></label>
        <div class="col-sm-10">
            <input asp-for="LastName" class="form-control">
        </div>
    </div>

    <div asp-validation-summary="All" class="text-danger"></div>

    <div class="form-group row">
        <div class="col-sm-10">
            <button type="submit" class="btn btn-primary">Update</button>
            <a asp-action="ListUsers" class="btn btn-primary">Cancel</a>
        </div>
    </div>

    <div class="card">
        <div class="card-header">
            <h3>User Roles</h3>
        </div>
        <div class="card-body">
            @if (Model.Roles.Any())
            {
                foreach (var role in Model.Roles)
                {
                    <h5 class="card-title">@role</h5>
                }
            }
            else
            {
                <h5 class="card-title">None at the moment</h5>
            }
        </div>
        <div class="card-footer">
            <a href="#" style="width:auto" class="btn btn-primary">
                Manage Roles
            </a>
        </div>
    </div>

    <div class="card mt-3">
        <div class="card-header">
            <h3>User Claims</h3>
        </div>
        <div class="card-body">
            @if (Model.Claims.Any())
            {
                foreach (var claim in Model.Claims)
                {
                    <h5 class="card-title">@claim</h5>
                }
            }
            else
            {
                <h5 class="card-title">None at the moment</h5>
            }
        </div>
        <div class="card-footer">
            <a href="#" style="width:auto" class="btn btn-primary">
                Manage Claims
            </a>
        </div>
    </div>
</form>
EditUser HttpPost Action

Next, add the following EditUser Post Action method to the AdministrationController. Here, we are using the UserManager service’s UpdateAsync method to update the data in the Identity database. The following code is self-explained, so please go through the comment lines for a better understanding.

[HttpPost]
public async Task<IActionResult> EditUser(EditUserViewModel model)
{
    //First Fetch the User by Id from the database
    var user = await _userManager.FindByIdAsync(model.Id);

    //Check if the User Exists in the database
    if (user == null)
    {
        //If the User does not exists in the database, then return Not Found Error View
        ViewBag.ErrorMessage = $"User with Id = {model.Id} cannot be found";
        return View("NotFound");
    }
    else
    {
        //If the User Exists, then proceed and update the data
        //Populate the user instance with the data from EditUserViewModel
        user.Email = model.Email;
        user.UserName = model.UserName;
        user.FirstName = model.FirstName;
        user.LastName = model.LastName;

        //UpdateAsync Method will update the user data in the AspNetUsers Identity table
        var result = await _userManager.UpdateAsync(user);

        if (result.Succeeded)
        {
            //Once user data updated redirect to the ListUsers view
            return RedirectToAction("ListUsers");
        }
        else
        {
            //In case any error, stay in the same view and show the model validation error
            foreach (var error in result.Errors)
            {
                ModelState.AddModelError("", error.Description);
            }
        }

        return View(model);
    }
}
UserManager UpdateAsync Method

The UpdateAsync method in ASP.NET Core Identity is part of the UserManager<TUser> class, where TUser is the user entity type, typically derived from IdentityUser. This method is used to update a user’s details in the database. This method is important for operations like changing a user’s email, username, or other personal information stored in the user entity. The method returns an IdentityResult, which indicates whether the operation was successful.

With the above changes in place, run the application and update the user details, and it should work as expected. In our upcoming articles, we will implement the Manage Roles and Manage Claims functionality.

In the next article, I will discuss How to Delete Identity User in ASP.NET Core. In this article, I explain How to Edit Identity Users in ASP.NET Core. I hope you enjoy this article, How to Edit ASP.NET Core Identity User.

Leave a Reply

Your email address will not be published. Required fields are marked *