-1

I have got this

  [HttpPost, ValidateAntiForgeryToken]
    public ActionResult Create(UserNew form)
    {
        var user = new User();
        SyncRoles(form.Roles, user.Roles);

        if (db.Users.Any(u => u.username == form.username))
        {
            ModelState.AddModelError("Username", "Username must be unique");
        }

        if (ModelState.IsValid)
        {
            user.username = form.username;
            user.email = form.email;                 
            user.SetPassword(form.password);

            db.Users.Add(user);
            db.SaveChanges();

            return RedirectToAction("Index");
        }

        return View(form);
    }

and with this function I am trying to get which checkboxes are checked in the form and assign the checked roles to the user:

 private void SyncRoles(IList<RoleCheckbox> checkboxes, IList<Role> roles)
    {
        var selectedRoles = new List<Role>();
        RolesContext rdb = new RolesContext();


        List <Role> roleList = new List<Role>();
        roleList = rdb.Roles.ToList();


        foreach (var role in roleList)
        {
            var checkbox = checkboxes.Single(c => c.roleId == role.roleId);
            checkbox.roleName = role.roleName;

            if (checkbox.IsChecked)
                selectedRoles.Add(role);
        }
        foreach (var toAdd in selectedRoles.Where(t => !roles.Contains(t)))
        {
            roles.Add(toAdd);
        }
        foreach (var toRemove in roles.Where(t => !selectedRoles.Contains(t)).ToList())
        {
            roles.Remove(toRemove);
        }
    }

When i try to create the user, I select the role "admin" (which already exists in the database with the id=1), in the database i get a new field in the Roles table with the name "admin" but a different ID. Can someone help me understand what am I doing wrong?

public class User
{
    [HiddenInput(DisplayValue = false)]
    public int userId { get; set; }

    [Required]
    [StringLength(128)]
    public string username { get; set; }

    [Required, DataType(DataType.EmailAddress)]
    [StringLength(256)]
    public string email { get; set; }

    [Required]
    [StringLength(128)]
    public string password_hash { get; set; }

    public virtual IList<Role> Roles { get; set; }

    public User()
    {
        Roles = new List<Role>();
    }

    public void SetPassword(string password)
    {
        password_hash = BCrypt.Net.BCrypt.HashPassword(password, 14);
    }
    public virtual bool CheckPassword(string password)
    {
        return BCrypt.Net.BCrypt.Verify(password, password_hash);
    }        
}

.

protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<User>()
            .Property(e => e.username)
            .IsUnicode(false);

        modelBuilder.Entity<User>()
            .Property(e => e.email)
            .IsUnicode(false);

        modelBuilder.Entity<User>()
            .Property(e => e.password_hash)
            .IsUnicode(false);

        modelBuilder.Entity<User>().HasMany(r => r.Roles).WithMany().Map(m =>
               {
                   m.ToTable("role_users");
                   m.MapLeftKey("user_Id");
                   m.MapRightKey("role_Id");
               });
    }
ricky
  • 1
  • 1
  • Why are you saving anything to your `Roles` table? You need to be saving Roles associated wth a User to a `UserRoles` table –  Dec 20 '16 at 02:10
  • @StephenMuecke yes, thats what I thought I have been doing... If i put a break point on the function ' SyncRoles(form.Roles, user.Roles);' in the ActionResult, i get the correct values for user.Roles - RoleId=1 and RoleName="admin" ... – ricky Dec 20 '16 at 02:44
  • No your not. You have a property `IList Roles`, but it needs to be `IList Roles` - you need a table for `UserRoles` to create the M-M relationships (with FK fields for `UserID` and `RoleID`). And as a side note, almost everything else you doing makes no sense, and I suggest you read [this answer](http://stackoverflow.com/questions/29542107/pass-list-of-checkboxes-into-view-and-pull-out-ienumerable/29554416#29554416) for how your models and view should look –  Dec 20 '16 at 02:48
  • @StephenMuecke, This role_users table gets populated with the new roleID and the correct role name... I would get something like userId =1000, roleId = 1000... – ricky Dec 20 '16 at 03:08

1 Answers1

0

I would like to add a comment, but is possible only after 50+ reputation. From what I see in your code, you assign roles to user from MVC and you are sending directly to EF, which lead you on duplicates in database. You should change the logic, and after you create user with success you should use UserManager class to add user to role:

UserManager.AddToRole(user.Id, role.Name);

where role is checked against database. If you have not find role in database you should created it using IdentityRole class

Ionut N
  • 434
  • 4
  • 9