userManager.AddToRoleAsync() - Error: role does not exist
userManager.AddToRoleAsync() - Error: role does not exist
我正在使用 .NET Core、Identity Core 和 MVC Core 创建用户注册系统。我能够在数据库中创建用户和创建角色。
这是视图上的表单,可以让我 select 一个用户和 select 添加一个角色:
@using (Html.BeginForm("AddRoleToUser", "Roles"))
{
@Html.AntiForgeryToken()
@Html.ValidationSummary(true)
<p>
Username : @Html.DropDownList("UserName", (IEnumerable<SelectListItem>)ViewBag.Users, "Select ...")
Role Name: @Html.DropDownList("RoleName", (IEnumerable<SelectListItem>)ViewBag.Roles, "Select ...")
</p>
<input type="submit" value="Save" />
}
这些下拉列表中填充了数据库中已经存在的用户和角色。他们允许我 select User
s 和我已经创建的角色的 name 。例如,我有一个名为 "admin" 的角色,这种形式让我 select 字符串 "admin".
这是处理向用户添加角色的操作:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> AddRoleToUser(string UserName, string RoleName)
{
try
{
ApplicationUser user = _db.Users.Where(u => u.UserName.Equals(UserName, StringComparison.CurrentCultureIgnoreCase)).FirstOrDefault();
await _userManager.AddToRoleAsync(user, RoleName);
PrepopulateDropDownMenus();
ViewBag.ResultMessage = "Role created successfully!";
return View("Manage", "Roles");
}
catch (Exception ex)
{
Console.WriteLine(ex);
return View("Manage");
}
}
该操作从未将角色添加到用户,异常显示为 "Role "ADMIN“不存在。”没有内部异常。我已经尝试将动作参数中的 RoleName
改为全大写,但仍然没有找到作用。我也尝试过使用角色 ID 代替名称,但也不成功。
当我使用带有 MVC 6 的 Identity 3.0 构建这个应用程序时,这个确切的代码有效。似乎在迁移到 Identity Core 时发生了一些变化。
有什么想法吗?
编辑
这是我用来通过 Viewbag 在 RolesController
中填充下拉列表的代码:
private void PrepopulateDropDownMenus()
{
var rolesList = _db.Roles.OrderBy(r => r.Name).ToList().Select(rr => new SelectListItem { Value = rr.Name.ToString(), Text = rr.Name }).ToList();
var usersList = _db.Users.OrderBy(u => u.UserName).ToList().Select(uu => new SelectListItem { Value = uu.UserName.ToString(), Text = uu.UserName }).ToList();
ViewBag.Roles = rolesList;
ViewBag.Users = usersList;
}
以下是我在 ConfigureServices
方法中的 Startup.cs 中添加身份的方法:
public void ConfigureServices(IServiceCollection services)
{
...
services.AddEntityFramework()
.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration["ConnectionStrings:DefaultConnection"]));
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
}
这是我在RolesController.cs中用来在数据库中创建新角色的路由:
[HttpPost]
public IActionResult Create(string rolename)
{
_db.Roles.Add(new IdentityRole()
{
Name = rolename
});
_db.SaveChanges();
ViewBag.ResultMessage = "Role created successfully!";
return RedirectToAction("Index");
}
我还不能post评论问你,所以,你的错误是说用户管理员不存在,还是角色不存在?我试图在我这边复制您的代码,如果用户不存在,您将收到 "user can't be null" 错误。但是,如果该角色不存在,您将收到 "Role [role] does not exist" 错误。
我假设您已经将该角色添加到您的数据库中?这是我在我的种子方法中使用的一些代码,基本上可以做你想做的,减去使用视图来做:
// Add the Admin role to the database
IdentityResult roleResult;
bool adminRoleExists = await _roleManager.RoleExistsAsync("Admin");
if (!adminRoleExists)
{
_logger.LogInformation("Adding Admin role");
roleResult = await _roleManager.CreateAsync(new IdentityRole("Admin"));
}
// Select the user, and then add the admin role to the user
ApplicationUser user = await _userManager.FindByNameAsync("sysadmin");
if (!await _userManager.IsInRoleAsync(user, "Admin"))
{
_logger.LogInformation("Adding sysadmin to Admin role");
var userResult = await _userManager.AddToRoleAsync(user, "Admin");
}
编辑
您现在添加角色的方式使角色 table 中的 NormalizedName 字段为空,我相信框架使用它来向用户添加角色。尝试使用以下方法之一向数据库添加角色,而不是您当前正在执行的操作:
var result = await _roleManager.CreateAsync(new IdentityRole(rolename));
或者这也可能有效(虽然还没有测试过):
[HttpPost]
public IActionResult Create(string rolename)
{
_db.Roles.Add(new IdentityRole()
{
Name = rolename,
NormalizedName = rolename.ToUpper()
});
_db.SaveChanges();
ViewBag.ResultMessage = "Role created successfully!";
return RedirectToAction("Index");
}
直接将其添加到数据库中是一个坏主意,并且违反了封装的所有概念,并且 NormalizedName 不是您应该自己计算的东西。
替换此代码:
var roleStore = new RoleStore<IdentityRole>(context);
await roleStore.CreateAsync(new IdentityRole(role));
以下内容:
var roleManager = services.GetService<RoleManager<IdentityRole>>();
await roleManager.CreateAsync(new IdentityRole(role));
确保在创建 AspNetRole 时,NormalizedName
不应为 null,以便 UserManager
正常工作。
NormalizedName 应该是 upper-case 使用 .ToUpper()
我正在使用 .NET Core、Identity Core 和 MVC Core 创建用户注册系统。我能够在数据库中创建用户和创建角色。
这是视图上的表单,可以让我 select 一个用户和 select 添加一个角色:
@using (Html.BeginForm("AddRoleToUser", "Roles"))
{
@Html.AntiForgeryToken()
@Html.ValidationSummary(true)
<p>
Username : @Html.DropDownList("UserName", (IEnumerable<SelectListItem>)ViewBag.Users, "Select ...")
Role Name: @Html.DropDownList("RoleName", (IEnumerable<SelectListItem>)ViewBag.Roles, "Select ...")
</p>
<input type="submit" value="Save" />
}
这些下拉列表中填充了数据库中已经存在的用户和角色。他们允许我 select User
s 和我已经创建的角色的 name 。例如,我有一个名为 "admin" 的角色,这种形式让我 select 字符串 "admin".
这是处理向用户添加角色的操作:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> AddRoleToUser(string UserName, string RoleName)
{
try
{
ApplicationUser user = _db.Users.Where(u => u.UserName.Equals(UserName, StringComparison.CurrentCultureIgnoreCase)).FirstOrDefault();
await _userManager.AddToRoleAsync(user, RoleName);
PrepopulateDropDownMenus();
ViewBag.ResultMessage = "Role created successfully!";
return View("Manage", "Roles");
}
catch (Exception ex)
{
Console.WriteLine(ex);
return View("Manage");
}
}
该操作从未将角色添加到用户,异常显示为 "Role "ADMIN“不存在。”没有内部异常。我已经尝试将动作参数中的 RoleName
改为全大写,但仍然没有找到作用。我也尝试过使用角色 ID 代替名称,但也不成功。
当我使用带有 MVC 6 的 Identity 3.0 构建这个应用程序时,这个确切的代码有效。似乎在迁移到 Identity Core 时发生了一些变化。
有什么想法吗?
编辑
这是我用来通过 Viewbag 在 RolesController
中填充下拉列表的代码:
private void PrepopulateDropDownMenus()
{
var rolesList = _db.Roles.OrderBy(r => r.Name).ToList().Select(rr => new SelectListItem { Value = rr.Name.ToString(), Text = rr.Name }).ToList();
var usersList = _db.Users.OrderBy(u => u.UserName).ToList().Select(uu => new SelectListItem { Value = uu.UserName.ToString(), Text = uu.UserName }).ToList();
ViewBag.Roles = rolesList;
ViewBag.Users = usersList;
}
以下是我在 ConfigureServices
方法中的 Startup.cs 中添加身份的方法:
public void ConfigureServices(IServiceCollection services)
{
...
services.AddEntityFramework()
.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration["ConnectionStrings:DefaultConnection"]));
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
}
这是我在RolesController.cs中用来在数据库中创建新角色的路由:
[HttpPost]
public IActionResult Create(string rolename)
{
_db.Roles.Add(new IdentityRole()
{
Name = rolename
});
_db.SaveChanges();
ViewBag.ResultMessage = "Role created successfully!";
return RedirectToAction("Index");
}
我还不能post评论问你,所以,你的错误是说用户管理员不存在,还是角色不存在?我试图在我这边复制您的代码,如果用户不存在,您将收到 "user can't be null" 错误。但是,如果该角色不存在,您将收到 "Role [role] does not exist" 错误。
我假设您已经将该角色添加到您的数据库中?这是我在我的种子方法中使用的一些代码,基本上可以做你想做的,减去使用视图来做:
// Add the Admin role to the database
IdentityResult roleResult;
bool adminRoleExists = await _roleManager.RoleExistsAsync("Admin");
if (!adminRoleExists)
{
_logger.LogInformation("Adding Admin role");
roleResult = await _roleManager.CreateAsync(new IdentityRole("Admin"));
}
// Select the user, and then add the admin role to the user
ApplicationUser user = await _userManager.FindByNameAsync("sysadmin");
if (!await _userManager.IsInRoleAsync(user, "Admin"))
{
_logger.LogInformation("Adding sysadmin to Admin role");
var userResult = await _userManager.AddToRoleAsync(user, "Admin");
}
编辑
您现在添加角色的方式使角色 table 中的 NormalizedName 字段为空,我相信框架使用它来向用户添加角色。尝试使用以下方法之一向数据库添加角色,而不是您当前正在执行的操作:
var result = await _roleManager.CreateAsync(new IdentityRole(rolename));
或者这也可能有效(虽然还没有测试过):
[HttpPost]
public IActionResult Create(string rolename)
{
_db.Roles.Add(new IdentityRole()
{
Name = rolename,
NormalizedName = rolename.ToUpper()
});
_db.SaveChanges();
ViewBag.ResultMessage = "Role created successfully!";
return RedirectToAction("Index");
}
直接将其添加到数据库中是一个坏主意,并且违反了封装的所有概念,并且 NormalizedName 不是您应该自己计算的东西。
替换此代码:
var roleStore = new RoleStore<IdentityRole>(context);
await roleStore.CreateAsync(new IdentityRole(role));
以下内容:
var roleManager = services.GetService<RoleManager<IdentityRole>>();
await roleManager.CreateAsync(new IdentityRole(role));
确保在创建 AspNetRole 时,NormalizedName
不应为 null,以便 UserManager
正常工作。
NormalizedName 应该是 upper-case 使用 .ToUpper()