List all Roles in Checkbox and mark the roles that the User has

Asked

Viewed 1,531 times

7

I am creating an Asp.net MVC 4 User Management System with two Simple Tables.

Users and Roles.

I can create users by selecting the roles they will own.

At the time of Edit I’m trying to List all the Roles in Checkbox and Mark Only the roles that the user has, so it is possible to change the user roles in the edition.

It goes down like I’m trying to do.

Controller

public ActionResult Edit(int id = 0)
{
    var usuario = _ctx.Usuarios.Include("Roles").ToList();
    var user = usuario.SingleOrDefault(u => u.UsuarioId == id);

    if (user == null)
    {
        return HttpNotFound();
    }

    ViewBag.Praca = new SelectList(_ctx.Pracas.ToList(), "PracaId", "Nome");
    ViewBag.Roles = _p.GetAllRoles();

    return View(user);
}

View Edit

<div class="col-lg-7">
    <h4>Permissões</h4>

    @foreach (var item in ViewBag.Roles)
    {
        foreach (var roles in Model.Roles)
        {
           <label style="display: block">
                <input type="checkbox" checked="@item.Equals(roles.Nome)" /> @item
           </label>
        }
     }
</div>

That way the data is coming duplicated.

Ex: Let’s say there are two roles "Admin" and "Manager" and the User has the Two, the output is:

[x] Admin
[ ] Admin
[ ] Gerente
[x] Gerente

If the User has only one of the Roles the Output goes the way I want it to go.

[x] Admin
[ ] Gerente
  • I have the same problem to solve a few weeks ago, I had to take other project priorities and I never corrected this situation!

4 answers

3


Firstly, your logic is not very good, because you are using two foreach nested, printing things on the page... that would be the logic of a table, but not of a list.

The correct logic for a list is to make the impression of the input within the first foreach, which is what iterates over all the input options there can be... from what I understand ViewBag.Roles contains all options of roles.

In addition, put checked="true" or checked="false" in your HTML will give in the same... both checkboxes will be selected. Not to select, the attribute checked must be removed entirely.

Just make it work:

<div class="col-lg-7">
    <h4>Permissões</h4>

    @foreach (var role in ViewBag.Roles)
    {
        bool estaSelecionado = false;
        foreach (var roleUsuario in Model.Roles)
        {
            if (roleUsuario.Nome == role)
            {
                estaSelecionado = true;
                break;
            }
        }

        <label style="display: block">
            @if (estaSelecionado)
            {
                <input type="checkbox" checked="checked" /> @role
            }
            else
            {
                <input type="checkbox" /> @role
            }
        </label>
     }
</div>

Now to simplify, you can use LINQ to Objects and write everything in a few lines.

EDIT

Since the simplicity is being questioned you can use the code below, which is more simple, uses LINQ, and has semantically correct Markup.

<div class="col-lg-7">
    <h4>Permissões</h4>

    @foreach (var role in ViewBag.Roles)
    {
        var roleId = "role-" + role.Replace(" ", "-");
        <div>
            @Html.CheckBox("role",
                    Model.Roles.Any(r => r.Nome == role),
                    new { value = role, id = roleId })
            <label for="@roleId">@role</label>
        </div>
     }
</div>

I would like to point out that the tag label is being misused in your code, the attribute is missing for... as I mentioned in the previous example.

I also noticed that you did not post your POST action to receive the data after editing... so I put all checkboxes with the same name, so you could do an action like this:

[HttpPost]
public ActionResult Edit(int id = 0, string[] role)
{
    // role contém uma lista dos roles selecionados, mas não contém os não selecionados
}
  • It worked perfectly Miguel, really my logic was totally wrong, thank you for the force.

  • @Hermesautran you have marked this option as a response and it actually works and is ok. But I recommend you take a look at the answer I posted below where the code is simpler and semantic.

  • @Miguelangelo the fact that he edited his version and bold the text "since simplicity is being questioned" seems to have sounded somewhat superb, with a certain lack of fair play. I’m sorry if I’m wrong. I have no intention of causing you discomfort or offense. The answer has already been accepted, if you saw any problem in my attempt to offer another opinion I can withdraw the comment and the answer without problems. Hugs.

  • @iuristona I saw no problem. As the comment was directly in my reply, I understood as an invitation to improve it. And the bold... man, it got really weird. It was a way of referring to the cause of the issue... but it does seem provocative. hehe =) Please do not remove anything.

  • I took out the bold, so it doesn’t look like it’s not.

  • iuristona and Miguelangelo The two forms worked and really solved my problem. I am studying the form given by the Gypsy on Membershipprovider and try to use the native methods of the classes, learned a lot from the solutions given. Thank you.

Show 1 more comment

3

Just complementing the answers: in MVC4 there are two classes and an attribute that implement authentication, user system and roles. They are they:

  • MembershipProvider
  • RoleProvider
  • AuthorizeAttribute

Just derive each and write the overrides. With this, you can use the native Framework methods, for example:

  • User.IsInRole("MinhaRole");
  • Roles.CreateRole("MinhaRole");

Or decorate your actions with the attribute [Authorize].

You can create sign-up screens and base your implementations on other models.

Examples:

Root Web.config

<system.web>
    <roleManager enabled="true" defaultProvider="MyRoleProvider">
      <providers>
        <clear />
        <add name="MyRoleProvider" type="TesteMaroto.Infrastructure.MyRoleProvider" connectionStringName="DefaultConnection" applicationName="/" />
      </providers>
    </roleManager>
    <membership defaultProvider="MyMembershipProvider">
      <providers>
        <clear />
        <add name="MyMembershipProvider" type="TesteMaroto.Infrastructure.MyMembershipProvider" connectionStringName="DefaultConnection" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="false" maxInvalidPasswordAttempts="5" minRequiredPasswordLength="6" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10" applicationName="/" />
      </providers>
    </membership>
    <machineKey validationKey="2183859A758E675951A39436AFD2FE57ABF398DA3627AE39B76075C995CF0094488F816CA5E6DA572627612C14F934589FF5B0CA92CC55F51F9099B10EB3F6F1" decryptionKey="8A46124FEC091DE2C82EDF529F884CC24CC8F38D6839A9FA6F86279DE5654261" validation="SHA1" decryption="AES" />
  </system.web>

Heed: Manages his <machineKey> here: http://aspnetresources.com/tools/machineKey

Membershipprovider

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Security;

namespace TesteMaroto.Infrastructure
{
    public class MyMembershipProvider : MembershipProvider
    {
        public override string ApplicationName
        {
            get
            {
                throw new NotImplementedException();
            }
            set
            {
                throw new NotImplementedException();
            }
        }

        /// <summary>
        /// Implemente aqui seu procedimento de alteração de senha.
        /// </summary>
        /// <param name="username">Login do Usuário</param>
        /// <param name="oldPassword">Senha antiga</param>
        /// <param name="newPassword">Nova senha</param>
        /// <returns>True se a operação foi feita com sucesso; False em caso contrário.</returns>
        public override bool ChangePassword(string username, string oldPassword, string newPassword)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Implemente este método se você quiser criar um esquema de recuperação de senha por pergunta e resposta.
        /// Este método altera a pergunta e a resposta.
        /// </summary>
        /// <param name="username">Login do Usuário</param>
        /// <param name="password">Senha</param>
        /// <param name="newPasswordQuestion">Nova pergunta para recuperação da senha</param>
        /// <param name="newPasswordAnswer">Nova resposta para recuperação da senha</param>
        /// <returns>True se a operação foi feita com sucesso; False em caso contrário.</returns>
        public override bool ChangePasswordQuestionAndAnswer(string username, string password, string newPasswordQuestion, string newPasswordAnswer)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Implemente este método um usuário e retorna um objeto do tipo MembershipUser preenchido.
        /// </summary>
        /// <param name="username">Login do Usuário</param>
        /// <param name="password">Senha</param>
        /// <param name="email">E-Mail</param>
        /// <param name="passwordQuestion">Pergunta para recuperação de senha</param>
        /// <param name="passwordAnswer">Resposta para recuperação de senha</param>
        /// <param name="isApproved">É aprovado ou precisa de uma confirmação extra, como aquelas enviadas por e-mail</param>
        /// <param name="providerUserKey">O objeto que representa a chave primária do seu model de usuário. Pode ser int, Guid...</param>
        /// <param name="status">Um objeto do Status da Criação. É preenchido dentro deste método</param>
        /// <returns>Objeto do tipo MembershipUser</returns>
        public override MembershipUser CreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, object providerUserKey, out MembershipCreateStatus status)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Implemente este método para excluir um usuário.
        /// </summary>
        /// <param name="username">Nome do usuário</param>
        /// <param name="deleteAllRelatedData">Indicativo para exclusão de todos os dados relacionados ao usuário.</param>
        /// <returns>True se a operação foi feita com sucesso; False em caso contrário.</returns>
        public override bool DeleteUser(string username, bool deleteAllRelatedData)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Implemente esta property para indicar ao Framework se você permite reiniciar a senha do usuário ou não.
        /// </summary>
        public override bool EnablePasswordReset
        {
            get { 
                // return true; ou então return false;
                throw new NotImplementedException();
            }
        }

        /// <summary>
        /// Implemente esta property para indicar ao Framework se você permite que a senha seja reenviada ao usuário caso ele assim solicite.
        /// </summary>
        public override bool EnablePasswordRetrieval
        {
            get {
                // return true; ou então return false;
                throw new NotImplementedException(); 
            }
        }

        /// <summary>
        /// Implemente este método para o Framework poder retornar todos os usuários cadastrados por um determinado e-mail.
        /// MembershipUserCollection é uma lista especial.
        /// </summary>
        /// <param name="emailToMatch">Endereço de e-mail a ser localizado</param>
        /// <param name="pageIndex">Índice da página. Serve para fazer paginação pra uma View, por exemplo</param>
        /// <param name="pageSize">Número de registros para uma página. Serve para fazer paginação pra uma View, por exemplo</param>
        /// <param name="totalRecords">Total de registros encontrados. Serve para fazer paginação pra uma View, por exemplo</param>
        /// <returns>Objeto do tipo MembershipUserCollection</returns>
        public override MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize, out int totalRecords)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Implemente este método para o Framework poder retornar todos os usuários cadastrados por um determinado nome.
        /// MembershipUserCollection é uma lista especial.
        /// </summary>
        /// <param name="usernameToMatch">Nome a ser localizado</param>
        /// <param name="pageIndex">Índice da página. Serve para fazer paginação pra uma View, por exemplo</param>
        /// <param name="pageSize">Número de registros para uma página. Serve para fazer paginação pra uma View, por exemplo</param>
        /// <param name="totalRecords">Total de registros encontrados. Serve para fazer paginação pra uma View, por exemplo</param>
        /// <returns>Objeto do tipo MembershipUserCollection</returns>
        public override MembershipUserCollection FindUsersByName(string usernameToMatch, int pageIndex, int pageSize, out int totalRecords)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Implemente este método para o Framework poder obter todos os usuários.
        /// </summary>
        /// <param name="pageIndex">Índice da página. Serve para fazer paginação pra uma View, por exemplo</param>
        /// <param name="pageSize">Número de registros para uma página. Serve para fazer paginação pra uma View, por exemplo</param>
        /// <param name="totalRecords">Total de registros encontrados. Serve para fazer paginação pra uma View, por exemplo</param>
        /// <returns>Objeto do tipo MembershipUserCollection</returns>
        public override MembershipUserCollection GetAllUsers(int pageIndex, int pageSize, out int totalRecords)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Implemente este método para o Framework poder retornar o número de usuários online.
        /// </summary>
        /// <returns>Número de usuários online.</returns>
        public override int GetNumberOfUsersOnline()
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Implemente este método para o Framework poder retornar a senha de um usuário baseado na resposta fornecida em tela.
        /// </summary>
        /// <param name="username">Login do usuário</param>
        /// <param name="answer">Resposta fornecida</param>
        /// <returns>Senha, se a resposta estiver correta.</returns>
        public override string GetPassword(string username, string answer)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Implemente este método para o Framework poder retornar todos os dados sobre um usuário procurando pelo Login do usuário.
        /// </summary>
        /// <param name="username">Login do usuário</param>
        /// <param name="userIsOnline">Indicativo de usuário online</param>
        /// <returns>Objeto do tipo MembershipUser</returns>
        public override MembershipUser GetUser(string username, bool userIsOnline)
        {
            throw new NotImplementedException();
        }
        /// <summary>
        /// Implemente este método para o Framework poder retornar todos os dados sobre um usuário procurando pela chave primária do Model.
        /// </summary>
        /// <param name="providerUserKey">A chave do Model (pode ser int, Guid...)</param>
        /// <param name="userIsOnline">Indicativo de usuário online</param>
        /// <returns>Objeto do tipo MembershipUser</returns>
        public override MembershipUser GetUser(object providerUserKey, bool userIsOnline)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Implemente este método para o Framework poder retornar o Login de um usuário procurando pelo e-mail do usuário.
        /// </summary>
        /// <param name="email">E-mail do usuário</param>
        /// <returns>Login do Usuário</returns>
        public override string GetUserNameByEmail(string email)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Implemente esta property para indicar ao Framework quantas tentativas erradas de senha tem um usuário antes da sua conta ser bloqueada.
        /// </summary>
        public override int MaxInvalidPasswordAttempts
        {
            get { throw new NotImplementedException(); }
        }

        /// <summary>
        /// Implemente esta property para indicar ao Framework quantos caracteres não-alfanuméricos deve ter a senha do usuário.
        /// </summary>
        public override int MinRequiredNonAlphanumericCharacters
        {
            get { throw new NotImplementedException(); }
        }

        /// <summary>
        /// Implemente esta property para indicar ao Framework a quantidade mínima de caracteres que deve ter a senha do usuário.
        /// </summary>
        public override int MinRequiredPasswordLength
        {
            get { throw new NotImplementedException(); }
        }

        /// <summary>
        /// Implemente esta property para indicar ao Framework o tempo da janela de tentativas de senha do usuário (em minutos).
        /// </summary>
        public override int PasswordAttemptWindow
        {
            get { throw new NotImplementedException(); }
        }

        /// <summary>
        /// Implemente esta property para indicar ao Framework o formato da senha do usuário.
        /// </summary>
        public override MembershipPasswordFormat PasswordFormat
        {
            get { throw new NotImplementedException(); }
        }

        /// <summary>
        /// Implemente esta property para indicar ao Framework a expressão regular que avalia a força da senha do usuário.
        /// </summary>
        public override string PasswordStrengthRegularExpression
        {
            get { throw new NotImplementedException(); }
        }

        /// <summary>
        /// Implemente esta property para indicar ao Framework se o registro do usuário requer pergunta e resposta para recuperação de senha.
        /// </summary>
        public override bool RequiresQuestionAndAnswer
        {
            get { throw new NotImplementedException(); }
        }

        /// <summary>
        /// Implemente esta property para indicar ao Framework se o e-mail deve ser único no registro de usuário.
        /// </summary>
        public override bool RequiresUniqueEmail
        {
            get { throw new NotImplementedException(); }
        }

        /// <summary>
        /// Implemente este método para indicar ao Framework como reiniciar e recuperar uma senha gerada pelo sistema para um usuário.
        /// </summary>
        /// <param name="username">Login do usuário</param>
        /// <param name="answer">Resposta de senha.</param>
        /// <returns>Nova senha gerada, se a resposta estiver correta.</returns>
        public override string ResetPassword(string username, string answer)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Implemente esta property para indicar ao Framework como desbloquear um usuário bloqueado no sistema.
        /// </summary>
        /// <param name="userName">Login do usuário</param>
        /// <returns>True se a operação foi feita com sucesso; False em caso contrário.</returns>
        public override bool UnlockUser(string userName)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Implemente esta property para indicar ao Framework como atualizar os dados de um usuário.
        /// </summary>
        /// <param name="user">Dados do usuário a ser atualizado.</param>
        public override void UpdateUser(MembershipUser user)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Implemente esta property para indicar ao Framework como validar um usuário para login.
        /// </summary>
        /// <param name="username">Login do usuário</param>
        /// <param name="password">Senha do usuário</param>
        /// <returns>True se usuário acertou a senha e pode se considerar autenticado; False em caso contrário.</returns>
        public override bool ValidateUser(string username, string password)
        {
            throw new NotImplementedException();
        }
    }
}

Roleprovider

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Security;

namespace TesteMaroto.Infrastructure
{
    public class MyRoleProvider : RoleProvider
    {
        /// <summary>
        /// Implemente este método para o Framework adicionar usuários a roles.
        /// </summary>
        /// <param name="usernames">Array de Logins.</param>
        /// <param name="roleNames">Roles às quais os usuários serão associados.</param>
        public override void AddUsersToRoles(string[] usernames, string[] roleNames)
        {
            throw new NotImplementedException();
        }

        public override string ApplicationName
        {
            get
            {
                throw new NotImplementedException();
            }
            set
            {
                throw new NotImplementedException();
            }
        }

        /// <summary>
        /// Implemente este método para o Framework criar uma Role.
        /// </summary>
        /// <param name="roleName">Nome da Role.</param>
        public override void CreateRole(string roleName)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Implemente este método para o Framework excluir uma Role.
        /// </summary>
        /// <param name="roleName">Nome da Role</param>
        /// <param name="throwOnPopulatedRole">Indicativo se deve haver uma exceção caso a exclusão seja de uma Role que tem usuários associados a ela</param>
        /// <returns>True se a operação foi feita com sucesso; False em caso contrário.</returns>
        public override bool DeleteRole(string roleName, bool throwOnPopulatedRole)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Implemente este método para o Framework procurar se um usuário está associado a uma Role.
        /// </summary>
        /// <param name="roleName">Nome da Role</param>
        /// <param name="usernameToMatch">Usuário para pesquisa</param>
        /// <returns>Lista de usuários encontrados</returns>
        public override string[] FindUsersInRole(string roleName, string usernameToMatch)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Implemente este método para o Framework retornar todas as Roles existentes.
        /// </summary>
        /// <returns>Array de Strings com o nome das Roles.</returns>
        public override string[] GetAllRoles()
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Implemente este método para o Framework retornar todas as Roles de um usuário.
        /// </summary>
        /// <param name="username">Login do usuário</param>
        /// <returns>Array de Strings com o nome das roles.</returns>
        public override string[] GetRolesForUser(string username)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Implemente este método para o Framework retornar todos os usuários de uma Role.
        /// </summary>
        /// <param name="roleName">Nome da Role</param>
        /// <returns>Array de Strings com os Logins dos usuários.</returns>
        public override string[] GetUsersInRole(string roleName)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Implemente este método para o Framework verificar se um usuário está em uma Role.
        /// </summary>
        /// <param name="username">Login do usuário</param>
        /// <param name="roleName">Nome da role</param>
        /// <returns>True se usuário está numa Role; False em caso contrário.</returns>
        public override bool IsUserInRole(string username, string roleName)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Implemente este método para o Framework remover usuários das Roles passadas como parâmetro.
        /// </summary>
        /// <param name="usernames">Logins dos usuários</param>
        /// <param name="roleNames">Nomes das Roles</param>
        public override void RemoveUsersFromRoles(string[] usernames, string[] roleNames)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Implemente este método para o Framework verificar se uma Role existe.
        /// </summary>
        /// <param name="roleName">Nome da Role</param>
        /// <returns>True se Role existe; False em caso contrário.</returns>
        public override bool RoleExists(string roleName)
        {
            throw new NotImplementedException();
        }
    }
}
  • If you could share some example I’d be very grateful!!

  • @Hermesautran I’m increasing the response as needed. Keep following.

  • can I use the class with a custom User Class if I don’t want Membershipprovider user properties? Ex: If you want the user to have, "Datanascimento", "Cpf", "City"...

  • @Hermesautran Then you need to derive MembershipUser. At the end of the afternoon I will put more examples.

  • 1

    Good idea to use Membership, but all ASP.NET is evolving to the use of ASP.NET Identity. This option to create new attributes that @Hermesautran asked about is simplified there. I suggest thinking about studying ASP.NET Identity directly. I currently use Membership and plan to migrate my application.

  • @iuristona I do not recommend it yet, mainly because the documentation related to Identity is still incomplete. I opened some questions in the gringo OS and I still have no answer. I had to go back to Membership.

  • @Gypsy omorrisonmendez could you paste here the questions? I’m studying Identity and I’m liking, in version 2.0 (beta2) has some good news, like being able to choose the type of PK that was just string, but in fact I know some restrictions.

  • @iuristona http://stackoverflow.com/questions/21785703/owin-customizing-usermanager e http://stackoverflow.com/questions/21817339/attempt-by-security-transparent-method-microsoft-web-helpers-preapplicationstar (the second is due to the update of the Packages to the newer versions of the Web Helpers).

  • @I posted something that maybe you can check out, back in the O.R..

Show 5 more comments

1

You have the existing roles on ViewBag.Roles, correct? Then your foreach should look like this:

@foreach (var role in ViewBag.Roles)
{
    <label style="display: block">
         <input type="checkbox" "@(Model.Roles.Select(n => n.Nome).Contains(role) ? "checked=checked" : "")" /> @role
    </label>
 }

Where Model.Roles.Select(n => n.Nome).Contains(role) ? "checked" : "" checks whether the Model.Roles contains that iteration role and assigns checked=checked at the checkbox.

  • I tested your example Iuri, but I get the following error! "The best method matching overloaded 'System.Collections.Generic.Icollection<App.Relatorio.Models.Role>. Contains(App.Relatorio.Models.Role)' has some invalid arguments"

  • Your answer is good... only missing a detail: in question the Model.Roles is a list of objects with the property Name, so a way to verify would be using LINQ: Model.Roles.Any(r => r.Nome == role) instead of using Contains. =)

  • I was assuming that ViewBag.Roles was a collection of Role, I see now that it’s a collection of string, I would change it differently: Model.Roles.Select(n => n.Name).Contains(role) purely by considering Contains more semantic than Any in this case.

0

The checked property is not boleana, once declared it selects alone.

Try using this in the View:

<div class="col-lg-7">
<h4>Permissões</h4>

@foreach (var item in ViewBag.Roles)
{
    foreach (var roles in Model.Roles)
    {
       <label style="display: block">
            @if(item.Equals(roles.Nome))
            {
                 <input type="checkbox" checked /> @item
            }
            else
            {
                 <input type="checkbox"/> @item 
            }
       </label>
    }
 }

  • It will duplicate the Checkbox the same way because it will check with all other roles and every time item. Equals(roles.Name) is not true it will print the unchecked check with the same name as the @item being checked! =/

Browser other questions tagged

You are not signed in. Login or sign up in order to post.