ASP .NET Core 3.1 - Usando o Identity de cabo a rabo - XV


Hoje vamos continuar a série de artigos mostrando como usar o ASP .NET Core Identiy na versão 3.1 da ASP .NET .Core e do EF Core.

Continuando a décima quarta parte do artigo veremos como editar uma role.

Editando uma role existente

Já vimos que uma role representa um perfil do usuário à qual podemos atribuir diversos usuários. Assim uma role possui associada a ela um ou mais de um usuário.

Para editar uma role existente vamos criar o método Action EditRole no controlador AdministrationController e precisamos passar o Id da role que desejamos editar.

Vamos então alterar o código da view ListRole onde no botão Editar vamos definir o nome do controlador, definir a Action e passar o Id da role usando :

@model IEnumerable<IdentityRole>
@{
    ViewBag.Title = "Todas as Roles";
}
<h1>Roles</h1>
@if (Model.Any())
{
    <a class="btn btn-primary mb-3" style="width:auto" asp-action="CreateRole"
       asp-controller="administration">Nova Role</a>
        ...
        ...
            <div class="card-footer">

                <a asp-action="EditRole" asp-controler="Administration"
                 asp-route-id="@role.Id" class="btn btn-primary">Editar</a>

                <a href="#" class="btn btn-danger">Deletar</a>
            </div>
        </div>
    }
}
...

Agora temos que criar a view model EditRoleViewModel com as propriedades relacionadas com o nome da role e com a lista de usuários que a role possui para podermos editar os dados.

Na pasta ViewModels crie a classe EditRoleViewModel conforme a seguir:

using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace FuncionariosWeb.ViewModels
{
    public class EditRoleViewModel
    {
        public EditRoleViewModel()
        {
            Users = new List<string>();
        }
        public string Id { get; set; }
        [Required(ErrorMessage = "O nome da role é obrigatório")]
        public string RoleName { get; set; }
        public List<string> Users { get; set; }
    }
}

Neste código estamos 3 propriedades :

A propriedade Users mantém representa a lista de usuários da role e esta sendo inicializada no construtor como uma lista de strings de forma a evitar uma exceção referência NULL.

Agora podemos definir os métodos Action EditRole HttpGet e HttpPost no controlador AdministrationController :

using FuncionariosWeb.Models;
using FuncionariosWeb.ViewModels;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using System.Threading.Tasks;
namespace FuncionariosWeb.Controllers
{
    public class AdministrationController : Controller
    {
        private readonly RoleManager<IdentityRole> roleManager;
        private readonly UserManager<ApplicationUser> userManager;
        public AdministrationController(RoleManager<IdentityRole> roleManager,
            UserManager<ApplicationUser> _userManager)
        {
            this.roleManager = roleManager;
            userManager = _userManager;
        }
        ...
        // O Id da Role é passado a partir da URL
        [HttpGet]
        public async Task<IActionResult> EditRole(string id)
        {
            // Localiza a role pelo ID
            var role = await roleManager.FindByIdAsync(id);
            if (role == null)
            {
                ViewBag.ErrorMessage = $"Role com Id = {id} não foi localizada";
                return View("NotFound");
            }
            var model = new EditRoleViewModel
            {
                Id = role.Id,
                RoleName = role.Name
            };
            var listaUsuarios = userManager.Users.ToList();
            // Retorna todos os usuários
            foreach (var user in listaUsuarios)
            {
                // Se o usuário existir na role, inclui o nome do usuário
                // para a propriedade Users de EditRoleViewModel
                // Este objeto model é então passado para ser exibido
                if (await userManager.IsInRoleAsync(user, role.Name))
                {
                    model.Users.Add(user.UserName);
                }
            }
            return View(model);
        }
        // Esta action responde ao POST e recebe a EditRoleViewModel
        [HttpPost]
        public async Task<IActionResult> EditRole(EditRoleViewModel model)
        {
            var role = await roleManager.FindByIdAsync(model.Id);
            if (role == null)
            {
                ViewBag.ErrorMessage = $"Role com Id = {model.Id} não foi encontrada";
                return View("NotFound");
            }
            else
            {
                role.Name = model.RoleName;
                // Atualiza a role usando UpdateAsync
                var result = await roleManager.UpdateAsync(role);
                if (result.Succeeded)
                {
                    return RedirectToAction("ListRoles");
                }
                foreach (var error in result.Errors)
                {
                    ModelState.AddModelError("", error.Description);
                }
                return View(model);
            }
        }
    }
}

Observe que precisamos injetar o serviço UserManager<ApplicationUser> no controlador para poder listar os usuários pertencentes a uma role.

Vamos criar a view EditRole para criar a interface que permite o usuário editar uma role e também incluir e remover um usuário de uma role.

@model EditRoleViewModel
@{
    ViewBag.Title = "Edita Role";
}
<h1>Edita Role</h1>
<form method="post" class="mt-3">
    <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="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">Atualiza</button>
            <a asp-action="ListRoles" class="btn btn-primary">Cancela</a>
        </div>
    </div>
    <div class="card">
        <div class="card-header">
            <h3>Usuários desta role</h3>
        </div>
        <div class="card-body">
            @if (Model.Users.Any())
            {
                foreach (var user in Model.Users)
                {
                    <h5 class="card-title">@user</h5>
                }
            }
            else
            {
                <h5 class="card-title">Sem usuários</h5>
            }
        </div>
        <div class="card-footer">
            <a href="#" class="btn btn-primary" style="width:auto">Incluir/Remover Usuário</a>
        </div>
    </div>
</form

No código desta view desabilitamos a edição do Id da role usando o atributo disable.

Implementamos a edição da role selecionada pelo seu Id e também a exibição dos usuários pertencentes a essa role definindo o botão para  Incluir e/ou Remover um usuário selecionado.

Vamos executar o projeto e navegar para http://localhost:xxxx/administration/listroles para obter a lista de roles:

Agora vamos clicar no botão Editar para exibir os dados da role Admin selecionada pelo seu ID para edição:

Observe que:

Vamos alterar o nome da role para Admin1 e clicar no botão Atualiza:

O nome será alterado e seremos redirecionados para ListRoles exibindo a alteração feita:

Assim já podemos alterar uma role existente.

No próximo artigo vamos implementar a inclusão e a remoção dos usuários de uma role.

"E, chegando-se Jesus, falou-lhes, dizendo: É-me dado todo o poder no céu e na terra."
Mateus 28:18

Referências:


José Carlos Macoratti