web-dev-qa-db-ja.com

userManager.AddToRoleAsync()-エラー:ロールが存在しません

.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を使用してこのアプリをビルドしたときに機能しました。IdentityCoreへの移行で何かが変わったようです。

何かご意見は?

編集

以下は、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にIDを追加する方法は次のとおりです。

    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");
    }
10
jmk22

まだコメントを投稿できないので、エラーにser adminが存在しない、またはroleが存在しないと表示されますか?コードを複製しようとしたところ、ユーザーが存在しない場合は、「ユーザーはnullにできません」というエラーが表示されます。ただし、役割が存在しない場合は、「役割[役割]が存在しません」というエラーが表示されます。

データベースにロールがすでに追加されていると思いますか?これは、基本的にユーザーが望むことを実行するシードメソッドで使用したいくつかのコードですが、ビューを使用して実行しています。

        // 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フィールドはnullのままです。これは、ユーザーにロールを追加するためのフレームワークで使用されていると思います。次のいずれかを試して、現在実行していることではなく、データベースにロールを追加します。

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");
}
16
FranksBrain

それをデータベースに直接追加することは悪い考えであり、カプセル化のすべての概念に違反しています。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));
0