使用ASP.NET身份验证更新用户角色

8

我有一个问题。 当使用下面的代码更改用户当前角色时,我会收到异常消息,如下所示:

    [HttpPost]
    [ValidateAntiForgeryToken]
    public virtual ActionResult Edit(User user, string role)
    {
        if (ModelState.IsValid)
        {
            var oldUser = DB.Users.SingleOrDefault(u => u.Id == user.Id);
            var oldRoleId = oldUser.Roles.SingleOrDefault().RoleId;
            var oldRoleName = DB.Roles.SingleOrDefault(r => r.Id == oldRoleId).Name;
            if (oldRoleName != role)
            {
                Manager.RemoveFromRole(user.Id, oldRoleName);
                Manager.AddToRole(user.Id, role);
            }
            DB.Entry(user).State = EntityState.Modified;

            return RedirectToAction(MVC.User.Index());
        }
        return View(user);
    }

附加类型为“Models.Entities.User”的实体失败,因为另一个具有相同主键值的实体已经存在。如果图形中的任何实体具有冲突的键值,则在使用“Attach”方法或将实体状态设置为“未更改”或“修改”时可能会发生此情况。这可能是因为某些实体是新的,并且尚未收到数据库生成的键值。在这种情况下,请使用“Add”方法或“Added”实体状态来跟踪图形,然后根据需要将非新实体的状态设置为“未更改”或“修改”。
有人知道解决这个问题的好方法吗?

1
你为什么要直接访问上下文?使用UserManager和RoleManager类会更容易且减少错误。UserManagerRoleManager 类是更好的选择。 - Horizon_Net
3个回答

17

问题在于您的经理和数据库不使用同一DbContext。因此,当您从DB的上下文发送用户到管理器时,它会将其处理为“新”的用户,然后您无法将其从角色中删除。这里有两种方法可供选择。最简单的方法是从您的经理获取用户。

[HttpPost]
[ValidateAntiForgeryToken]
public virtual ActionResult Edit(User user, string role)
{
    if (ModelState.IsValid)
    {
        // THIS LINE IS IMPORTANT
        var oldUser = Manager.FindById(user.Id);
        var oldRoleId = oldUser.Roles.SingleOrDefault().RoleId;
        var oldRoleName = DB.Roles.SingleOrDefault(r => r.Id == oldRoleId).Name;

        if (oldRoleName != role)
        {
            Manager.RemoveFromRole(user.Id, oldRoleName);
            Manager.AddToRole(user.Id, role);
        }
        DB.Entry(user).State = EntityState.Modified;

        return RedirectToAction(MVC.User.Index());
    }
    return View(user);
}

更优雅的方式是开始使用依赖注入框架,例如AutoFac (https://code.google.com/p/autofac/wiki/MvcIntegration),并将您的DbContext设置为InstancePerApiRequest。

builder.RegisterType<YourDbContext>().As<DbContext>().InstancePerApiRequest();

0

我的角色是在DbMigrationsConfiguration类的种子方法中管理的,我将其重命名为:

        if (context.Roles.Any(r => r.Name == "User"))
        {
            var store = new RoleStore<IdentityRole>(context);
            var manager = new RoleManager<IdentityRole>(store);
            var role = manager.Roles.First(r => r.Name == "User");

            role.Name = "NewNameForUser";
            manager.Update(role);
        }

0
在 Identity Version 6.0.8 中 它对我有效。
if (role != currentrole)
            {
                _context.UserRoles.Remove(userIdData);
                _context.SaveChanges();
                userIdData.RoleId = aspnetroleId.Single();
                userIdData.UserId = userId;
                _context.UserRoles.Add(userIdData);
                _context.SaveChanges();         
                                    
            }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接