How to Create, Read, Update & Delete users in Identity Membership System in ASP.NET Core

How to Create, Read, Update & Delete users in Identity Membership System in ASP.NET Core

With my ASP.NET Core Identity system set up I am now ready to use it. Here I will do the CRUD Operations for Creating, Reading, Updating and Deleting Users from the Identity system.

In the last tutorial I explained the Setup and Configuration of Identity Membership System, if you missed it then first look into it.

Creating Users in Identity

To create Users in Identity Membership System I will need to create a Model Class. So create a class called ‘User.cs’ inside the Models folders.

Add 3 public properties to it, which are Name, Email & Password, of type string. Also add ‘Required’ Model validations to it using Data Annotations method:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.ComponentModel.DataAnnotations;

namespace Identity.Models
{
    public class User
    {
        [Required]
        public string Name { get; set; }
        
        [Required]
        [RegularExpression("^[a-zA-Z0-9_\\.-][email protected]([a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,6}$", ErrorMessage = "E-mail is not valid")]
        public string Email { get; set; }

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

Next, create ‘Controllers’ folder in the root of your project, and there create a new Controller called ‘Admin’ inside the Controllers folder.

Inside the Admin Controller I will perform all the CRUD Operations.

The first thing to do in the Controller is to get the instance of UserManager through Dependency Injection. This class is use to for managing users, here I will use it to create a new User.

The updated code for the Admin Controller is given below:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Identity.Models;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;

namespace Filters.Controllers
{
    public class AdminController : Controller
    {
        private UserManager<AppUser> userManager;

        public AdminController(UserManager<AppUser> usrMgr)
        {
            userManager = usrMgr;
        }

        public IActionResult Index()
        {
            return View();
        }
    }
}

Next, I need to add a Create action method that will actually create a new user in the Identity System. So add it to your Admin controller as shown by the code below:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Identity.Models;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;

namespace Filters.Controllers
{
    public class AdminController : Controller
    {
        private UserManager<AppUser> userManager;

        public AdminController(UserManager<AppUser> usrMgr)
        {
            userManager = usrMgr;
        }

        public IActionResult Index()
        {
            return View();
        }

        public ViewResult Create() => View();

        [HttpPost]
        public async Task<IActionResult> Create(User user)
        {
            if (ModelState.IsValid)
            {
                AppUser appUser = new AppUser
                {
                    UserName = user.Name,
                    Email = user.Email
                };

                IdentityResult result = await userManager.CreateAsync(appUser, user.Password);
                if (result.Succeeded)
                    return RedirectToAction("Index");
                else
                {
                    foreach (IdentityError error in result.Errors)
                        ModelState.AddModelError("", error.Description);
                }
            }
            return View(user);
        }
    }
}

The Create Action method (POST Version) is the one which creates the new user. It takes an argument of the User class and checks if the Model State is valid or not.

I also have written a tutorial on previous version of Entity Framework, and in that tutorial I did CRUD Operations in ASP.NET WebForms. You can read this tutorial at – CRUD Operations in Entity Framework and ASP.NET

If the Model State is valid then it creates a new instance of ‘AppUser’ class, and gives it the Username and Emails as provided in the ‘User’ class object from the form in the View. The associated code for this is:

AppUser appUser = new AppUser
{
    UserName = user.Name,
    Email = user.Email
};

After this, I create the user from the UserManager class CreateAsync method. As you remember I get this class object through Dependency Injection.

To the CreateAsync method I provided the AppUser class object and the password provided from the form. Once the User is created I get the return value of type IdentityResult. The associated code for this is:

IdentityResult result = await userManager.CreateAsync(appUser, user.Password);

The IdentityResult Class has the following properties:

  • Succeeded – this property returns true if the create user operation completes successfully.
  • Errors – this property returns an object of type IEnumerable that contains the errors occurred when performing the create user operation. The IdentityError has a Description property which gives the description of each of the error that happened.

I use the Succeeded property of the IdentityResult class to find out if the create user operation completed successfully or not.

If it completed successfully then I am redirecting to the Index View else I am adding all the error descriptions in the Model State. The associated code is given below:

if (result.Succeeded)
    return RedirectToAction("Index");
else
{
    foreach (IdentityError error in result.Errors)
        ModelState.AddModelError("", error.Description);
}

If the Model State is invalid then I am returning to the Create View where the errors will be shown to the user so that he can correct them and try once again.

Now it’s time to add the Create View inside the ‘Views/Admin/’ folder with the following code:

@model User

<h1 class="bg-info text-white">Create User</h1>
<a asp-action="Index" class="btn btn-secondary">Back</a>
<div asp-validation-summary="All" class="text-danger"></div>

<form method="post">
    <div class="form-group">
        <label asp-for="Name"></label>
        <input asp-for="Name" class="form-control" />
    </div>
    <div class="form-group">
        <label asp-for="Email"></label>
        <input asp-for="Email" class="form-control" />
    </div>
    <div class="form-group">
        <label asp-for="Password"></label>
        <input asp-for="Password" class="form-control" />
    </div>
    <button type="submit" class="btn btn-primary">Create</button>
</form>

The View has a simple form which is used to create a new user in the Identity system. The form contains 3 input controls for – Name, Email and Password, these values MVC binds to the properties of the Model class that is passed to the create action method.

You can now create a new user by running your project and go to the URL – ‘/Admin/Create’.

Fill Name, Email and Password (as shown in the below image), and click the ‘Create’ button.

create user identity

Once the User is created you will be redirected to the Index View. The Index View will show the entire User account stored in the Identity database. I will create this feature next.

You cannot create a same user again. If you again go to the Create URUL and fill details of a User who is already created then you will see an error message saying – ‘User name ‘Yogi’ is already taken.

Reading all Users of Identity System

All the User accounts of Identity System can be fetched by the ‘Users’ property of the UserManager class. The Users property will return an IEnumerable object.

So change the Index Action method code to as shown in the below code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Identity.Models;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;

namespace Filters.Controllers
{
    public class AdminController : Controller
    {
        private UserManager<AppUser> userManager;

        public AdminController(UserManager<AppUser> usrMgr)
        {
            userManager = usrMgr;
        }

        public IActionResult Index()
        {
            return View(userManager.Users);
        }

        // removed for clarity
    }
}

Now, create an Index View inside the ‘Views/Admin’ folder. In this View all the details of the Identity Users will be shown:

@model IEnumerable<AppUser>

<h1 class="bg-info text-white">All Users</h1>
<a asp-action="Create" class="btn btn-secondary">Create a User</a>

<table class="table table-sm table-bordered">
    <tr><th>ID</th><th>Name</th><th>Email</th></tr>
    @foreach (AppUser user in Model)
    {
    <tr>
        <td>@user.Id</td>
        <td>@user.UserName</td>
        <td>@user.Email</td>
    </tr>
    }
</table>

The View receives a Model of type IEnumerable. I am looping over all the users using for each loop and showing them inside a table.

You can now check the Reading all Users functionality by going to the URL – ‘/Admin’, which will invoke the Index Action method.

The Image below shows the User records that are currently there in my Identity Database:

all users identity

Updating Users of Identity System

Now I will do the updating of the Identity System Users. For this add a new column called ‘Update’ in the table given in the Index View. In this column I will create an anchor tag that will link to the ‘Update’ Action method.

So add a new ‘th’ element to the table and also add a new ‘td’ element inside the ‘tr’ element. The ‘td’ element will contains the anchor tag.

The updated code of the Index View is given below:

...
<table class="table table-sm table-bordered">
    <tr><th>ID</th><th>Name</th><th>Email</th><th>Update</th></tr>
    @foreach (AppUser user in Model)
    {
    <tr>
        <td>@user.Id</td>
        <td>@user.UserName</td>
        <td>@user.Email</td>
        <td><a class="btn btn-sm btn-primary" asp-action="Update" asp-route-id="@user.Id">Update</a></td>
    </tr>
    }
</table>

Before creating the Update Action method to the Admin controller, I will need to add a dependency of IPasswordHasher in the constructor. It is used to get the hashed value of the password of the new password provided by the user.

Note that in Identity System passwords are stored in Hashed value instead of plain text. This gives added security.

So update the constructor code as shown below:

private UserManager<AppUser> userManager;
private IPasswordHasher<AppUser> passwordHasher;

public AdminController(UserManager<AppUser> usrMgr, IPasswordHasher<AppUser> passwordHash)
{
    userManager = usrMgr;
    passwordHasher = passwordHash;
}

Next, add the Update action method to the Admin controller. The code is given below:

public async Task<IActionResult> Update(string id)
{
    AppUser user = await userManager.FindByIdAsync(id);
    if (user != null)
        return View(user);
    else
        return RedirectToAction("Index");
}

[HttpPost]
public async Task<IActionResult> Update(string id, string email, string password)
{
    AppUser user = await userManager.FindByIdAsync(id);
    if (user != null)
    {
        if (!string.IsNullOrEmpty(email))
            user.Email = email;
        else
            ModelState.AddModelError("", "Email cannot be empty");

        if (!string.IsNullOrEmpty(password))
            user.PasswordHash = passwordHasher.HashPassword(user, password);
        else
            ModelState.AddModelError("", "Password cannot be empty");

        if (!string.IsNullOrEmpty(email) && !string.IsNullOrEmpty(password))
        {
            IdentityResult result = await userManager.UpdateAsync(user);
            if (result.Succeeded)
                return RedirectToAction("Index");
            else
                Errors(result);
        }
    }
    else
        ModelState.AddModelError("", "User Not Found");
    return View(user);
}

private void Errors(IdentityResult result)
{
    foreach (IdentityError error in result.Errors)
        ModelState.AddModelError("", error.Description);
}

The GET Version of the Update Action takes a string user’s id value. It then fetches the User’s information from the Identity Database using the FindByIdAsync method of the UserManger class. The FindByIdAsync method is provided with the Id of the User in string format.

The associated code is:

AppUser user = await userManager.FindByIdAsync(id);

Once the User’s information is fetched, it is then send to the Update View as model.

The Post version of the Update Action is where the updation of the User’s information is done. This action is invoked when the user click the submit button on the form given in the Update View.

First I fetch the User’s information in an AppUser object by using the FindByIdAsync() method:

AppUser user = await userManager.FindByIdAsync(id);

Then, if the AppUser object is not null, I proceed by checking if the new email and password values given by the user are not empty.

If they contain some value then I update the Email and PasswordHash property values of the AppUser object to the new ones provided by the user.

See the below code which does this work:

if (!string.IsNullOrEmpty(email))
    user.Email = email;
else
    ModelState.AddModelError("", "Email cannot be empty");

if (!string.IsNullOrEmpty(password))
    user.PasswordHash = passwordHasher.HashPassword(user, password);
else
    ModelState.AddModelError("", "Password cannot be empty");

Note that I use the HashPassword method to get the Hashed value of the new password provided by the user:

user.PasswordHash = passwordHasher.HashPassword(user, password);

Finally, when the email and password values are not empty then I updated them using the UpdateAsync method. This method takes the AppUser object. The associated code is given below:

if (!string.IsNullOrEmpty(email) && !string.IsNullOrEmpty(password))
{
    IdentityResult result = await userManager.UpdateAsync(user);
    if (result.Succeeded)
        return RedirectToAction("Index");
    else
        Errors(result);
}

In case if the UpdateAsync method does not completes successfully then the Errors method is called to add the IdentityResult type errors to the Model State. The Error method code:

void Errors(IdentityResult result)
{
    foreach (IdentityError error in result.Errors)
        ModelState.AddModelError("", error.Description);
}

Now, create the Update View inside the ‘Views/Admin’ folder with the following code:

@model AppUser

<h1 class="bg-info text-white">Update User</h1>
<a asp-action="Index" class="btn btn-secondary">Back</a>
<div asp-validation-summary="All" class="text-danger"></div>

<form asp-action="Update" method="post">
    <div class="form-group">
        <label asp-for="Id"></label>
        <input asp-for="Id" class="form-control" disabled />
    </div>
    <div class="form-group">
        <label asp-for="Email"></label>
        <input asp-for="Email" class="form-control" />
    </div>
    <div class="form-group">
        <label for="password">Password</label>
        <input name="password" class="form-control" />
    </div>
    <button type="submit" class="btn btn-primary">Save</button>
</form>

You can now test the update feature by going to the ‘/Admin’ URL. There click the Update button which will take you to the Update page.

Add new Email and password and click the save button. This will update the User record stored in the Identity database.

The below image illustrates the Update feature:

update user identity

Deleting Users of Identity System

The final CRUD operation is the Delete one, which is done by the Delete Action method of type Post. This action method code is given below, add the code to your Admin Controller:

[HttpPost]
public async Task<IActionResult> Delete(string id)
{
    AppUser user = await userManager.FindByIdAsync(id);
    if (user != null)
    {
        IdentityResult result = await userManager.DeleteAsync(user);
        if (result.Succeeded)
            return RedirectToAction("Index");
        else
            Errors(result);
    }
    else
        ModelState.AddModelError("", "User Not Found");
    return View("Index", userManager.Users);
}

The Action method receives the User Id and it fetches the user details using the FindByIdAsync method. I get the User details in an AppUser object.

Then I use the DeleteAsync method to delete the user from the Identity database. The below code does the delete work:

IdentityResult result = await userManager.DeleteAsync(user);

If the delete operation completes successfully then I redirect to the Index Action method else the ‘Errors’ method is called to show the errors to the user.

The delete button needs to be added to the table of the Index View. Add a new ‘th’ element called ‘Delete’ to the table, and also add a new ‘td’ element that will contains a form (with action ‘Delete’ & route-id as the user id) and a button.

The updated code of the Index View is given below:

...
<table class="table table-sm table-bordered">
    <tr><th>ID</th><th>Name</th><th>Email</th><th>Update</th><th>Delete</th></tr>
    @foreach (AppUser user in Model)
    {
        <tr>
            <td>@user.Id</td>
            <td>@user.UserName</td>
            <td>@user.Email</td>
            <td><a class="btn btn-sm btn-primary" asp-action="Update" asp-route-id="@user.Id">Update</a></td>
            <td>
                <form asp-action="Delete" asp-route-id="@user.Id" method="post">
                    <button type="submit" class="btn btn-sm btn-danger">
                        Delete
                    </button>
                </form>
            </td>
        </tr>
    }
</table>

Run your application and go to the URL- ‘/Admin’. Here you will see the User records have a delete button. When you click the delete button then the corresponding user record will be deleted from the Identity database.

See the below image:

delete record identity

You can download the full codes of this tutorial from the below link:

Download

Conclusion

This completes the procedure to manage user in Identity system. You can now add, update, read and delete users from Identity database.

In the next tutorial on Identity I created Username, Email & Password Policy which will help you to create your own custom rules in Identity.

Share this article -

yogihosting

ABOUT THE AUTHOR

This article has been written by the Technical Staff of YogiHosting. Check out other articles on "WordPress, SEO, jQuery, HTML" and more.