userManager.AddToRoleAsync() - 错误:角色不存在

Posted

技术标签:

【中文标题】userManager.AddToRoleAsync() - 错误:角色不存在【英文标题】:userManager.AddToRoleAsync() - Error: role does not exist 【发布时间】:2017-01-23 21:58:32 【问题描述】:

我正在使用 .NET Core、Identity Core 和 MVC Core 创建一个用户注册系统。我能够在数据库中创建用户和创建角色。

这是视图上的表单,让我可以选择用户并选择要添加的角色:

@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" />

这些下拉列表中填充了数据库中已存在的用户和角色。它们允许我选择 Users 以及我已经创建的角色的 name。例如,我有一个名为“admin”的角色,这个表单让我选择字符串“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");
        
    

该操作从未向用户添加角色,并且异常显示“角色“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");
    

【问题讨论】:

【参考方案1】:

我还不能发布 cmets 来问你,那么,你的错误是说 user admin 不存在,还是 role 不存在?我试图复制您的代码,如果用户不存在,您将收到“用户不能为空”错误。但是,如果角色不存在,您将收到“角色 [角色] 不存在”错误。

我假设您已经将该角色添加到您的数据库中?这是我在种子方法中使用的一些代码,基本上可以满足您的需求,但需要使用视图来完成:

        // 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");
        

编辑

您现在添加角色的方式使 Role 表中的 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");

【讨论】:

感谢您的关注!错误显示“角色 [角色] 不存在”。我已经编辑了我的问题。我已经将角色添加到我的数据库中(下拉列表中填充了“角色”表中的数据)。您在答案中包含的代码对您有用吗? 是的,这是我用来播种新/空数据库的实际代码,但基础应该是相同的。您可以发布填充您的选择列表的代码吗?以及如何将角色添加到数据库中? 这很有趣。我在上面的编辑中添加了代码。我在控制器的 Create 操作中使用数据库的 Add 方法将角色添加到数据库。 这很奇怪。我复制/粘贴了您的代码,它对我来说效果很好。我知道这对你没有帮助,但我想知道现在还有什么可能。您使用的是最新的 .Net Core 版本吗?您的 startup.cs 的 Identity 部分看起来如何?我在这里挖掘,但想复制这个问题 这就是我做它导致它失败的相同方式!请改用 RoleManager 创建角色。用我在答案中的代码(或类似的代码)替换您的代码。以下应该至少可以工作: var result = await _roleManager.CreateAsync(new IdentityRole(rolename));我相信这是因为您添加它的方式使 Roles 表中的 NormalizedName 字段为空。或者,您可以添加参数 NormalizedName = rolename.ToUpper() 也可以修复它。【参考方案2】:

确保在创建 AspNetRole 时,NormalizedName 不应为空,以便 UserManager 正常工作。

NormalizedName 应为大写,使用 .ToUpper()

【讨论】:

【参考方案3】:

将它直接添加到数据库是一个坏主意,并且违反了封装的所有概念,而且 NormalizedName 不是您应该自己计算的东西。

See this answer

替换此代码:

var roleStore = new RoleStore<IdentityRole>(context);
await roleStore.CreateAsync(new IdentityRole(role));

以下内容:

var roleManager = services.GetService<RoleManager<IdentityRole>>();
await roleManager.CreateAsync(new IdentityRole(role));

【讨论】:

我同意这是处理此案的更好方式。我也举了这个例子,实际上是在 cmets 中提出的。但是,我并没有强调直接访问数据库是一种不好的做法,所以谢谢你。

以上是关于userManager.AddToRoleAsync() - 错误:角色不存在的主要内容,如果未能解决你的问题,请参考以下文章