Roles Management in ASP.NET Core Identity

Roles Management in ASP.NET Core Identity

In this article, I will discuss Roles Management, i.e., How to Add, Update, Retrieve, and Delete Roles in ASP.NET Core Identity. Please read our previous article discussing Customizing AspNetUsers Table in ASP.NET Core Identity. At the end of this article, you will understand how to create a new role, fetch all the roles, fetch a specific role, and update and delete an existing role using ASP.NET Core Identity.

Roles Management in ASP.NET Core Identity

Managing roles in ASP.NET Core Identity involves adding, updating, displaying, and deleting roles. To do this, we need to work with the RoleManager class. The RoleManager Class in ASP.NET Core Identity provides the methods for managing roles in your application. The following are the Key Features of the RoleManager Class in ASP.NET Core Identity:

  • Role Creation and Deletion: You can create and delete roles using RoleManager.
  • Role Retrieval: It allows you to retrieve roles from the database.
  • Role Updating: You can update role information.
  • Role Checking: You can check if a certain role exists in the database.

The following is the database table in the ASP.NET Core Identity where we are going to store all the roles and perform the database CRUD operations:

How to Use RoleManager in ASP.NET Core?

The above database table is created from the following IdentityRole generic model class of the ASP.NET Core Identity Framework.

IdentityRole generic model class

Example to Understand CRUD Operations to Manage Roles in ASP.NET Core:

Let us see an Example to Understand How to Perform CRUD Operations to Manage Roles in ASP.NET Core Identity. For this purpose, we create a new MVC empty controller named AdministrationController. Once you create the AdministrationController, copy and paste the following code. As you can see, within the constructor, we inject the RoleManager and specify the IdentityRole as a parameter to perform the operations on the database table mapped with this IdentityRole type, i.e., AspNetRoles.

using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;

namespace ASPNETCoreIdentityDemo.Controllers
{
    public class AdministrationController : Controller
    {
        private readonly RoleManager<IdentityRole> _roleManager;

        public AdministrationController(RoleManager<IdentityRole> roleManager)
        {
            _roleManager = roleManager;
        }
    }
}

Add a Role using ASP.NET Core Identity:

A Role in ASP.NET Core Identity is used for Role-Based Authorization or Role-Based Access Control (RBAC), where different users can be assigned to different roles, and these roles can be used to control access to various parts of your application. First, you need to define what roles are required for your application, such as, Admin, SuperAdmin, User, Sales, Moderator, etc. The following CreateAsync method of the RoleManager<TRole> class is used to create a new role.

Method Signature: Task<IdentityResult> CreateAsync(TRole role);

Here, TRole is the type of the role, which by default is IdentityRole but can be a custom role class if you’ve extended the IdentityRole.

  • Parameters: The method takes a single parameter, an instance of the TRole class. This instance contains the details of the role you want to create, such as its name.
  • Return Type: The method returns Task<IdentityResult>. IdentityResult indicates the success or failure of the role creation operation. It contains details about any errors that occurred if the operation was unsuccessful.
Creating CreateRoleViewModel

Let us proceed and see how we can add a new Role. To add a new role, we will use the following CreateRoleViewModel class. So, create a class file named CreateRoleViewModel.cs within the Models folder and copy and paste the following code. In ASP.NET Core, the Role name must be unique in the database. Here, we decorated the RoleName property with the [Required] attribute as it is a required field.

using System.ComponentModel.DataAnnotations;
namespace ASPNETCoreIdentityDemo.Models
{
    public class CreateRoleViewModel
    {
        [Required]
        [Display(Name = "Role")]
        public string RoleName { get; set; }
    }
}
Modifying the Administration Controller

So, to add a new role, please add the following two action methods to the Administration Controller. The Get version of the CreateRole action method renders a view using which we can add a new user. The Post version of the CreateRole action method adds the new role to the database using the RoleManager service. Here, we are also using the RoleExistsAsync method to check whether the role name already exists in the database. The CreateAsync method adds a new role to the AspNetRoles table.

[HttpGet]
public IActionResult CreateRole()
{
    return View();
}

[HttpPost]
public async Task<IActionResult> CreateRole(CreateRoleViewModel roleModel)
{
    if (ModelState.IsValid)
    {
        // Check if the role already exists
        bool roleExists = await _roleManager.RoleExistsAsync(roleModel?.RoleName);
        if (roleExists)
        {
            ModelState.AddModelError("", "Role Already Exists");
        }
        else
        {
            // Create the role
            // We just need to specify a unique role name to create a new role
            IdentityRole identityRole = new IdentityRole
            {
                Name = roleModel?.RoleName
            };

            // Saves the role in the underlying AspNetRoles table
            IdentityResult result = await _roleManager.CreateAsync(identityRole);

            if (result.Succeeded)
            {
                return RedirectToAction("Index", "Home");
            }

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

    return View(roleModel);
}
Create Role View:

Next, add a view named CreateRole.cshtml within the /Views/Administration directory and copy and paste the following code.

@model CreateRoleViewModel

@{
    ViewBag.Title = "Create New Role";
}

<form asp-action="CreateRole" method="post" class="mt-3">
    <div asp-validation-summary="All" class="text-danger">
    </div>
    <div class="form-group row">
        <label asp-for="RoleName" class="col-sm-2 col-form-label"></label>
        <div class="col-sm-10">
            <input asp-for="RoleName" class="form-control" placeholder="Name">
            <span asp-validation-for="RoleName" class="text-danger"></span>
        </div>
    </div>

    <div class="form-group row">
        <div class="col-sm-10">
            <button type="submit" class="btn btn-primary" style="width:auto">
                Create Role
            </button>
        </div>
    </div>
</form>

With the above changes in place, run the application and go to the URL /Administration/CreateRole. You should see the following page. Provide the Role name and click the Create Role button, as shown in the image below.

Add a Role using ASP.NET Core Identity

Once you click on the Create Role button, it should create the Role, and you can verify the same in the AspNetRoles table, as shown in the image below:

Add a Role using ASP.NET Core Identity

In the same way, you can also add other Roles as per your requirement, such as SuperAdmin, User, etc. Please add these SuperAdmin and User Roles as well using the same approach.

Listing Roles (Read Operation) in ASP.NET Core Identity:

Now, we will see how to retrieve and display all roles in the ASP.NET Core MVC Application using the ASP.NET Core Identity. It does not require the details page, as it only includes the Role name, which we display on the list page. On the list page, we want to display

  • Role ID
  • Role Name and
  • A Pair of Buttons to Edit and Delete a Role

So, basically, we want the list page to be displayed as follows:

Listing Roles (Read Operation) in ASP.NET Core Identity

How Do We Fetch All Roles in ASP.NET Core Identity?

The Roles property of the RoleManager class returns the list of all IdentityRole objects. Then, we need to pass this List<IdentityRole> role objects to the view for display. So, add the following ListRoles action method within the AdministrationController.

[HttpGet]
public async Task<IActionResult> ListRoles()
{
    List<IdentityRole> roles = await _roleManager.Roles.ToListAsync();
    return View(roles);
}
Creating List Roles View:

Now, let us add the ListRoles view to display the list of roles. So, create a view named ListRoles.cshtml within /Views/Administration directory and then copy and paste the following code:

@using Microsoft.AspNetCore.Identity
@model IEnumerable<IdentityRole>

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

<h1>All Roles</h1>

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

    foreach (var role in Model)
    {
        <div class="card mb-3">
            <div class="card-header">
                Role Id : @role.Id
            </div>
            <div class="card-body">
                <h5 class="card-title">@role.Name</h5>
            </div>
            <div class="card-footer">
                <a href="#" 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 roles created yet
        </div>
        <div class="card-body">
            <h5 class="card-title">
                Use the button below to create a role
            </h5>
            <a class="btn btn-primary" style="width:auto"
               asp-controller="administration" asp-action="CreateRole">
                Create Role
            </a>
        </div>
    </div>
} 

Here,

  • The ID property of the IdentityRole object returns the role ID.
  • The Name property of the IdentityRole object returns the role Name.
  • The model for this view is IEnumerable<IdentityRole>.
  • IdentityRole belongs to Microsoft.AspNetCore.Identity namespace.

With the above changes in place, run the application, navigate to /Administration/ListRoles URL and it should display the List of Roles along with the Edit and Delete buttons as expected. But if you click on the Edit and Delete buttons, then nothing will happen. Let us proceed and implement these two functionalities:

Edit Role in ASP.NET Core Identity:

Editing Roles in ASP.NET Core Identity involves retrieving the existing role information from the database, displaying it in a form for editing (usually the role name), and then saving the changes to the database. Let us proceed and see how we can implement this in our ASP.NET Core MVC Application:

Creating EditRoleViewModel:

Create a view model to represent the data on the edit role page. So, create a class file named EditRoleViewModel.cs and then copy and paste the following code: This class has two properties: Id Property is to hold the Role Id, which is unique and mandatory, and RollName Property, which is also going to be unique and mandatory.

using System.ComponentModel.DataAnnotations;

namespace ASPNETCoreIdentityDemo.Models
{
    public class EditRoleViewModel
    {
        [Required]
        public string Id { get; set; }
        [Required(ErrorMessage = "Role Name is Required")]
        public string RoleName { get; set; }
    }
}
Retrieve Role Details

First, you need to fetch the role details you want to edit. So, to get the Role details from the database, you need to call the FindByIdAsync method by passing the RoleId. So, add the following GET version of the EditRole action method within the AdministrationController. Here, you can see this method takes the RoleId as an input parameter and then fetches the data from the database based on the RoleId. If the role exists in the database, it creates and populates an instance of the EditRoleViewModel and then passes that EditRoleViewModel object to the view.

[HttpGet]
public async Task<IActionResult> EditRole(string roleId)
{
    //First Get the role information from the database
    IdentityRole role = await _roleManager.FindByIdAsync(roleId);
    if (role == null)
    {
        // Handle the scenario when the role is not found
        return View("Error");
    }

    //Populate the EditRoleViewModel from the data retrived from the database
    var model = new EditRoleViewModel
    {
        Id = role.Id,
        RoleName = role.Name
        // You can add other properties here if needed
    };

    return View(model);
}
Create the Edit Role View:

Next, create a view named EditRole.cshtml and copy and paste the following code. This view presents a form for editing the role. Its model is EditRoleViewModel.

@model EditRoleViewModel

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

<h1>Edit Role</h1>

<form method="post" class="mt-3">
    <div class="form-group row">
        <input type="hidden" asp-for="Id" />
        <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="RoleName" class="col-sm-2 col-form-label"></label>
        <div class="col-sm-10">
            <input asp-for="RoleName" class="form-control">
            <span asp-validation-for="RoleName" class="text-danger"></span>
        </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="ListRoles" class="btn btn-primary">Cancel</a>
        </div>
    </div>

</form>
Handle the Post Request

When the form is submitted, it should send a POST request to an action method that handles the update logic. We need to use the following UpdateAsync method of the RoleManager class to update the Role. The UpdateAsync method in the RoleManager<TRole> class is used to update an existing role entity in the identity database. 

Signature: Task<IdentityResult> UpdateAsync(TRole role);

Parameters:
  • role: This parameter, TRole, represents the role you want to update. TRole is typically IdentityRole or a custom role class derived from IdentityRole.
Return Type:
  • Task<IdentityResult>: Since UpdateAsync is an asynchronous method, it returns a Task. The IdentityResult object encapsulates the result of the role update operation. It indicates whether the operation was successful and contains details about any errors that occurred if the operation was unsuccessful.

So, add the following POST version of the EditRole action method within the AdministrationController.

[HttpPost]
public async Task<IActionResult> EditRole(EditRoleViewModel model)
{
    if (ModelState.IsValid)
    {
        var role = await _roleManager.FindByIdAsync(model.Id);
        if (role == null)
        {
            // Handle the scenario when the role is not found
            ViewBag.ErrorMessage = $"Role with Id = {model.Id} cannot be found";
            return View("NotFound");
        }
        else
        {
            role.Name = model.RoleName;
            // Update other properties if needed

            var result = await _roleManager.UpdateAsync(role);
            if (result.Succeeded)
            {
                return RedirectToAction("ListRoles"); // Redirect to the roles list
            }

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

            return View(model);
        }
    }

    return View(model);
}
Modifying the List Role View to Add the Update Role Link:

Next, modify the ListRoles.cshtml view to modify the Edit Role link as follows. Here, we are specifying the Edit link’s action method (EditRole) and controller name (Administration). 

@using Microsoft.AspNetCore.Identity
@model IEnumerable<IdentityRole>

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

<h1>All Roles</h1>

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

    foreach (var role in Model)
    {
        <div class="card mb-3">
            <div class="card-header">
                Role Id : @role.Id
            </div>
            <div class="card-body">
                <h5 class="card-title">@role.Name</h5>
            </div>
            <div class="card-footer">
                <a asp-controller="Administration" asp-action="EditRole"
                   asp-route-roleId="@role.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 roles created yet
        </div>
        <div class="card-body">
            <h5 class="card-title">
                Use the button below to create a role
            </h5>
            <a class="btn btn-primary" style="width:auto"
               asp-controller="Administration" asp-action="CreateRole">
                Create Role
            </a>
        </div>
    </div>
}

With the above changes in place, run the application and navigate to /Administration/ListRoles URL, which should open the below page. Now, click the Edit button of the Role you want to update. Let us click on the User Role edit button.

Edit Role in ASP.NET Core Identity

Once you click the User Role Edit button, the following page will open. It displays the Role ID in non-editable mode and the Role Name in editable mode. If you click the Cancel button, you will be taken back to the Roles List page.

Edit Role in ASP.NET Core Identity

Now, let us update the Role User to Sales and click on the Edit button as shown in the below image:

Edit Role in ASP.NET Core Identity

Once you click on the Update button, the data will be updated in the AspNetRoles table, redirected to the Roles List page, and shown in the image below.

Edit Role in ASP.NET Core Identity

Delete Role in ASP.NET Core Identity:

Now, we will see how to delete IdentityRole from the AspNetRoles database table using the ASP.NET Core Identity. Deleting a Role in ASP.NET Core Identity involves finding the role by its ID and removing it using the RoleManager. When the Delete button is clicked, the respective role must be deleted from the AspNetRoles table.

So what we want is when the user clicks the Delete button in the Roles List Page, we want to display a delete confirmation message before actually deleting the role. So, the following is our Roles List page displaying all the Roles.

Delete Role in ASP.NET Core Identity

When the user clicks on the Delete button, we want to display the delete confirmation message with Yes and No options, as shown in the below image:

Roles Management, i.e., How to Add, Update, Retrieve, and Delete Roles in ASP.NET Core Identity

When the user clicks the Yes button, the role should be deleted from the AspNetRoles database table and redirected to the Roles list page. Let us proceed and see how we can implement this.

Modifying ListRoles.cshtml View

First, modify the ListRoles.cshtml view as follows:

@using Microsoft.AspNetCore.Identity
@model IEnumerable<IdentityRole>

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

<h1>All Roles</h1>

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

    foreach (var role in Model)
    {
        <div class="card mb-3">
            <div class="card-header">
                Role Id : @role.Id
            </div>
            <div class="card-body">
                <h5 class="card-title">@role.Name</h5>
            </div>
            <div class="card-footer">

                <form asp-action="DeleteRole" asp-route-roleId="@role.Id" method="post">

                    <a asp-controller="Administration" asp-action="EditRole"
                       asp-route-roleId="@role.Id" class="btn btn-primary">
                        Edit
                    </a>

                    <span id="confirmDeleteSpan_@role.Id" style="display:none">
                        <span>Are you sure you want to Delete?</span>
                        <button type="submit" class="btn btn-danger">Yes</button>
                        <a href="#" class="btn btn-primary"
                           onclick="confirmDelete('@role.Id', false)">No</a>
                    </span>

                    <span id="deleteSpan_@role.Id">
                        <a href="#" class="btn btn-danger"
                           onclick="confirmDelete('@role.Id', true)">Delete</a>
                    </span>
                </form>

            </div>
        </div>
    }
}
else
{
    <div class="card">
        <div class="card-header">
            No roles created yet
        </div>
        <div class="card-body">
            <h5 class="card-title">
                Use the button below to create a role
            </h5>
            <a class="btn btn-primary" style="width:auto"
               asp-controller="Administration" asp-action="CreateRole">
                Create Role
            </a>
        </div>
    </div>
}

<script>
    function confirmDelete(uniqueId, isTrue) {

        var deleteSpan = 'deleteSpan_' + uniqueId;
        var confirmDeleteSpan = 'confirmDeleteSpan_' + uniqueId;

        if (isTrue) {
            $('#' + deleteSpan).hide();
            $('#' + confirmDeleteSpan).show();
        } else {
            $('#' + deleteSpan).show();
            $('#' + confirmDeleteSpan).hide();
        }
    }
</script>

Here,

  • The Yes button type is set to submit. It is placed inside the form element, and the method attribute is set to post.
  • So, when the Yes button is clicked, a POST request is issued to the DeleteRole() action method, passing it the ID of the role to delete.
  • The span elements surrounding the Delete, Yes, and No buttons will be dynamically generated for every role on the list page.
  • If you have more than one role on the page, there will be more than one span element.
  • To ensure these span elements have unique IDs, we are appending Role.Id, which is a Guid and guaranteed to be unique.

Note: It’s a good practice to ask for confirmation before performing a delete operation. This can be done by showing a confirmation dialog or redirecting to a confirmation page. But in modern web applications, we show the confirmation message at the same line.

How do you Delete a Role in an ASP.NET Core Identity?

In ASP.NET Core Identity, the DeleteAsync method of the RoleManager<TRole> class is used to delete a role. The signature of this method is as follows:

Task<IdentityResult> DeleteAsync(TRole role);

Parameters:
  • role: The parameter TRole represents the role you want to delete. TRole is typically an instance of IdentityRole or a custom role class derived from IdentityRole.
Return Type:
  • Task<IdentityResult>: DeleteAsync is an asynchronous method that returns a Task. The IdentityResult object encapsulates the result of the role deletion operation. It indicates whether the operation was successful and contains details about any errors that occurred if the operation was unsuccessful.

So, add the following HttpPost DeleteRole action method into the AdministrationController.

[HttpPost]
public async Task<IActionResult> DeleteRole(string roleId)
{
    var role = await _roleManager.FindByIdAsync(roleId);
    if (role == null)
    {
        // Role not found, handle accordingly
        ViewBag.ErrorMessage = $"Role with Id = {roleId} cannot be found";
        return View("NotFound");
    }

    var result = await _roleManager.DeleteAsync(role);
    if (result.Succeeded)
    {
        // Role deletion successful
        return RedirectToAction("ListRoles"); // Redirect to the roles list page
    }

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

    // If we reach here, something went wrong, return to the view
    return View("ListRoles", await _roleManager.Roles.ToListAsync());
}

With these changes in place, run the application and test the delete functionality, and it should work as expected.

In the next article, I will discuss Customizing the AspNetRoles Table in ASP.NET Core Identity. In this article, I explain Role Management in ASP.NET Core Identity. I hope you enjoy this Roles Management, i.e., How to Add, Update, Retrieve, and Delete Roles in the ASP.NET Core Identity article.

Leave a Reply

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