如何在.NET Core 2中更新身份用户角色的扩展UserRole

时间:2018-12-25 23:14:25

标签: .net-core

我们扩展了身份用户(ApplicationUser)角色(ApplicationRole) UserRole(ApplicationUserRole)

我们设法保存了对ApplicationUser的更改,但能够使用以下代码在ApplicationUserRole上保存更改:

public async Task<IActionResult> OnPostAsync(Guid id)
    {
        if (!ModelState.IsValid)
        {
            return Page();
        }

        var userToUpdate = await _context.Users
            .FirstOrDefaultAsync(m => m.Id == id.ToString());

        var userRoleToUpdate = await _context.UserRoles
                                        .FirstOrDefaultAsync(m => m.UserId == id.ToString());

        // null means User was deleted by another user.
        if (userToUpdate == null || userRoleToUpdate == null)
        {
            return await HandleDeletedUser();
        }

        // Update the RowVersion to the value when this entity was
        // fetched. If the entity has been updated after it was
        // fetched, RowVersion won't match the DB RowVersion and
        // a DbUpdateConcurrencyException is thrown.
        // A second postback will make them match, unless a new 
        // concurrency issue happens.

        _context.Entry(userToUpdate)
            .Property("RowVersion").OriginalValue = User.RowVersion;

        if (await TryUpdateModelAsync<ApplicationUser>(
            userToUpdate,
            "User",
            s => s.FirstName, s => s.LastName, s => s.Email))
        {
            try
            {
                await _context.SaveChangesAsync();

                if (await TryUpdateModelAsync<ApplicationUserRole>(
                   userRoleToUpdate,
                   "UserRole",
                   s => s.RoleId.ToString()))
                {
                    await _context.SaveChangesAsync();
                }


                return RedirectToPage("./Index");
            }
            catch (DbUpdateConcurrencyException ex)
            {
                var exceptionEntry = ex.Entries.Single();
                var clientValues = (ApplicationUser)exceptionEntry.Entity;
                var databaseEntry = exceptionEntry.GetDatabaseValues();
                if (databaseEntry == null)
                {
                    ModelState.AddModelError(string.Empty, "Unable to save. " +
                        "The user was deleted by another user.");
                    return Page();
                }

                var dbValues = (ApplicationUser)databaseEntry.ToObject();
                await setDbErrorMessage(dbValues, clientValues, _context);

                // Save the current RowVersion so next postback
                // matches unless an new concurrency issue happens.

                User.RowVersion = (byte[])dbValues.RowVersion;

                // Must clear the model error for the next postback.
                ModelState.Remove("User.RowVersion");
            }
        }

        return Page();


    }

对此有任何指针吗?我以为我们需要分解保存更改。先是User然后是UserRole,不是吗?

此外,我们没有为 ApplicationUserRole 实施 RowVersion ,我认为这太过头了。

环境: .Net Core 2.1

更新-1:

例外- InvalidOperationException:传递的表达式节点类型'Call'的表达式无效。仅支持模型属性的简单成员访问表达式。

更新-2:

我已更改为此,但没有错误,但角色没有更改:

if (await TryUpdateModelAsync<ApplicationUserRole>(
                   userRoleToUpdate,
                   "UserRole",
                   ur => ur.UserId, ur => ur.RoleId))
                {
                    await _context.SaveChangesAsync();
                }

与编辑表单(Edit.html)上的下拉列表中的更新该RoleId相比,我们如何进行映射?!?!

<div class="form-group">
            Role:
            <select asp-for="User.UserRoles.ElementAt(0).RoleId" class="form-control"
                    asp-items="@Model.RoleNameSL">
                <option value="">-- Select Role --</option>
            </select>
            <span asp-validation-for="User.UserRoles.ElementAt(0).Role" class="text-danger"></span>
        </div>

更新-3:

这很有趣。我将文本从“ UserRole”更改为“”:

if (await TryUpdateModelAsync<ApplicationUserRole>(
                   userRoleToUpdate,
                   "",
                   ur => ur.RoleId))
                {
                    await _context.SaveChangesAsync();
                }

现在我们有一个错误,说我认为这已经接近了:

  

InvalidOperationException:实体类型上的属性'RoleId'   'ApplicationUserRole'是密钥的一部分,因此无法进行修改或   标记为已修改。用以下方法更改现有实体的主体   标识外键首先删除依赖项并调用   然后,“ SaveChanges”将依赖项与新的主体相关联。

是否可能因为我们的ApplicationDBContext中有此对象?在那种情况下,什么是最好的更新方式呢?

protected override void OnModelCreating(ModelBuilder builder)
{

       ....  

        // Many to Many relationship - ApplicationUserRole

        builder.Entity<ApplicationUserRole>(userRole =>
        {
            userRole.HasKey(ur => new { ur.UserId, ur.RoleId });

            userRole.HasOne(ur => ur.Role)
                .WithMany(r => r.UserRoles)
                .HasForeignKey(ur => ur.RoleId)
                .IsRequired();

            userRole.HasOne(ur => ur.User)
                .WithMany(r => r.UserRoles)
                .HasForeignKey(ur => ur.UserId)
                .IsRequired();
        });
    }

1 个答案:

答案 0 :(得分:1)

如果您使用的外观像AspNetIdentity,则应该能够使用UserManager更新角色。 UserManager是Identity的一部分,用于管理用户的身份。只要您的角色为AspNetRoles,然后注入UserManager就可以将任何用户更新为任何预定义的角色。

添加

private readonly UserManager<ApplicationUser> _userManager;

public Controller(UserManager<ApplicationUser> userManger, ApplicationUser applicationUser)
{ 
    _userManager = userManger;
}

public async Task UpDateRole(string userId)
{
    var user = await _userManager.FindByIdAsync(userId);
    var result = await _userManager.AddToRoleAsync(userId, "RoleName");
}

应该做您想做的事,您可能还想将该用户从以前的角色中删除。