将Viewmodel返回给HttpPost ActionResult

时间:2017-11-10 19:10:18

标签: c# asp.net asp.net-mvc mvvm asp.net-identity

我试图更新我的用户集合'我的ASP.NET身份项目中的角色,但我目前卡住了,因为我在发送到UsersAndRolesDictionary方法的ViewModel中获得了一个null [HttpPost]属性。

这是我的ViewModel,UpdateUserRolesViewModel

namespace Project_Name.Models
{
    public class UpdateUserRolesViewModel
    {
        public IDictionary<ApplicationUser, ICollection<IdentityUserRole>> UsersAndRolesDictionary { get; set; } // <-- This is returning null currently
    }
}

这是HomeController方法:

[Authorize(Roles = "Admin")]
public ActionResult RoleManager()
{
    ViewBag.Message = "Role Management Page";

    var databaseContext = new ApplicationDbContext();           // Get the Database Context
    var users = databaseContext.Users.Include(u => u.Roles);    // Get all users from the Database and their Roles

    var newDict = new Dictionary<ApplicationUser, ICollection<IdentityUserRole>>();

    // Add each user and their roles to the dictionary
    foreach (var user in users)
    {
        newDict.Add(user, user.Roles);
    }

    // Update the ViewModel with the collection of users and roles
    var updateUserRolesViewModel = new UpdateUserRolesViewModel {UsersAndRolesDictionary = newDict};

    return View(updateUserRolesViewModel);
}

[HttpPost]
[Authorize(Roles = "Admin")]
[ValidateAntiForgeryToken]
public async Task<ActionResult> UpdateUsersRolesAsync(UpdateUserRolesViewModel updateUserRolesViewModel)
{
    try
    {
        //TODO: Attempt to update the user roles or delete the user
        return View("RoleManager");
    }
    catch
    {
        //TODO: Properly catch errors
        return View("RoleManager");
    }
}

以下是我的观点,RoleManager

@using Project_Name.Models

@model UpdateUserRolesViewModel

@{
    ViewBag.Title = "Role Manager";
    var databaseContext = new ApplicationDbContext();   // Get the Database Context
    var roles = databaseContext.Roles;                  // Get all Roles from the database, use this to compare against
}

<h2>@ViewBag.Title</h2>

<div class="row">
    <div class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
        @using (Html.BeginForm("UpdateUsersRolesAsync", "Home", FormMethod.Post))
        {
            @Html.AntiForgeryToken()

            <div class="form-group">
                <div class="table-responsive">
                    <table class="table table-striped table-bordered table-hover">
                        <thead>
                            <tr>
                                <th>Email</th>
                                <th>Roles</th>
                                <th>Delete User?</th>
                            </tr>
                        </thead>
                        <tbody>
                            @{
                                int i = 0; // Used to make unique IDs for the user's table row, and deleteUserCheckbox
                                int j = 0; // Used to make unique IDs for the role checkboxes
                                foreach (var user in Model.UsersAndRolesDictionary.Keys)
                                {
                                    i++;
                                    <tr id="userTableRow_@i">
                                        <td>@user.Email</td>
                                        <td>
                                            @* Show each role availabe as a checkbox. Check them if the user has that role. *@
                                            @foreach (var role in roles)
                                            {
                                                @Html.CheckBox("userRoleCheckbox_" + j++, user.Roles.Any(identityUserRole => identityUserRole.RoleId.Contains(role.Id)))
                                                <span>@role.Name</span>
                                                <br />
                                            }
                                        </td>
                                        <td>
                                            @Html.CheckBox("deleteUserCheckbox_" + i)
                                            <span>Delete User</span>
                                        </td>
                                    </tr>
                                }
                            }
                        </tbody>
                    </table>
                </div>

                @* Reset and Submit buttons *@
                <div class="col-lg-2 col-lg-push-8 col-md-2 col-md-push-8 col-sm-2 col-sm-push-8 col-xs-2 col-xs-push-8">
                    <input type="reset" class="btn btn-danger btn-block" value="Reset" />
                </div>
                <div class="col-lg-2 col-lg-push-8 col-md-2 col-md-push-8 col-sm-2 col-sm-push-8 col-xs-2 col-xs-push-8">
                    <input type="submit" class="btn btn-primary btn-block" value="Submit" />
                </div>

            </div>
        }
    </div>
</div>

我使用字典UsersAndRolesDictionary来收集所有用户及其角色,然后通过它进行枚举,以表格的形式生成我的视图。

我希望更改潜在多个用户的复选框值,然后将更新后的ViewModel传递给我的[HttpPost] UpdateUsersRolesAsync方法,以便更新我的用户角色,但是现在我已经&#39;我得到UsersAndRolesDictionary属性的空值,我不知道为什么或如何解决它。

<小时/> 感谢Stephen Muecke在评论中的链接/答案,我能够回答这个问题。请参阅下面的回答。

1 个答案:

答案 0 :(得分:0)

根据评论中Stephen Muecke的建议,我已经获得了有效的ViewModel。

添加/更新了三个组合在一起的ViewModel:

第一个是RoleViewModel

public class RoleViewModel
{
    public string Id { get; set; }
    public string Name { get; set; }
    public bool IsSelected { get; set; }
}

第二个是UserViewModel

public class UserViewModel
{
    public string Id { get; set; }
    public string Email { get; set; }
    public List<RoleViewModel> RoleViewModels { get; set; }
    public bool DeleteUser { get; set; } // Doesn't work yet, might be in the wrong place
}

最后,第三个是UpdateUserRoleViewModel的更新版本:

public class UpdateUserRolesViewModel
{
    public int Id { get; set; }
    public List<UserViewModel> UserViewModels { get; set; }
}

在我更新的HomeController中再次使用这些方法:

[Authorize(Roles = "Admin")]
public ActionResult RoleManager()
{
    ViewBag.Message = "Role Management Page";

    var databaseContext = new ApplicationDbContext();                   // Get the Database Context
    var users = databaseContext.Users.Include(u => u.Roles).ToList();   // Get all users from the Database and their Roles

    // Create the UpdateUserRolesViewModel
    var updateUserRolesViewModel = new UpdateUserRolesViewModel
    {
        Id = 0, // Not sure what else the Id would be
        UserViewModels = new List<UserViewModel>()
    };

    // Add each user to the UserViewModels list
    for (int i = 0; i < users.Count(); i++)
    {
        var userViewModel = new UserViewModel
        {
            Id = users.AsEnumerable().ElementAt(i).Id,
            Email = users.AsEnumerable().ElementAt(i).UserName,
            RoleViewModels = new List<RoleViewModel>(),
            DeleteUser = false
        };

        // Add each role from the Roles table to the RoleViewModels list, check if user has that role
        foreach (var role in databaseContext.Roles)
        {
            var roleViewModel = new RoleViewModel
            {
                Id = role.Id,
                Name = role.Name,
                IsSelected = users.AsEnumerable().ElementAt(i).Roles.Any(identityUserRole => identityUserRole.RoleId.Contains(role.Id))
            };

            userViewModel.RoleViewModels.Add(roleViewModel);
        }

        updateUserRolesViewModel.UserViewModels.Add(userViewModel);
    }

    return View(updateUserRolesViewModel);
}

[HttpPost]
[Authorize(Roles = "Admin")]
[ValidateAntiForgeryToken]
public async Task<ActionResult> UpdateUsersRolesAsync(UpdateUserRolesViewModel updateUserRolesViewModel)
{
    try
    {
        // Attempt to update the user roles
        foreach (var user in updateUserRolesViewModel.UserViewModels)
        {
            // Delete user
            //TODO: Prompt user to confirm deletion if one or more people are being deleted
            if (user.DeleteUser)
            {
                var userToDelete = await UserManager.FindByIdAsync(user.Id);    // Get the ApplicationUser object of who we want to delete
                await UserManager.DeleteAsync(userToDelete);                    // Delete the user
                continue;                                                       // Don't try to update the roles of a deleted user.
            }

            // Remove all roles from the User
            var rolesToRemove = await UserManager.GetRolesAsync(user.Id);
            await UserManager.RemoveFromRolesAsync(user.Id, rolesToRemove.ToArray());

            // Add roles to the User
            foreach (var roleViewModel in user.RoleViewModels.Where(r => r.IsSelected))
            {
                await UserManager.AddToRoleAsync(user.Id, roleViewModel.Name);
            }
        }

        return RedirectToAction("RoleManager");
    }
    catch
    {
        //TODO: Properly catch errors
        return RedirectToAction("RoleManager");
    }
}

最后,这是我的视图, RoleManager

@using Project_Name.ViewModels

@model UpdateUserRolesViewModel

@{
    ViewBag.Title = "Role Manager";
}

@* Debugging text *@
@foreach (var user in Model.UserViewModels)
{
    <div>User ID: @user.Id</div>
    <div>User Name: @user.Email</div>
    <p>
        @foreach (var roleViewModel in user.RoleViewModels.Where(r => r.IsSelected))
        {
            <div>Role ID: @roleViewModel.Id</div>
            <div>Role Name: @roleViewModel.Name</div>
        }
    </p>
    <hr />
}

<h2>@ViewBag.Title</h2>

<div class="row">
    <div class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
        @using (Html.BeginForm("UpdateUsersRolesAsync", "Home", FormMethod.Post))
        {
            @Html.AntiForgeryToken()
            @Html.HiddenFor(m => m.Id)
            <div class="form-group">
                <div class="table-responsive">
                    <table class="table table-striped table-bordered table-hover">
                        <thead>
                            <tr>
                                <th>Email</th>
                                <th>Roles</th>
                                <th>Delete User?</th>
                            </tr>
                        </thead>
                        <tbody>
                            @for (int i = 0; i < Model.UserViewModels.Count; i++)
                            {
                                <tr id="userTableRow_@i">
                                    <td>
                                        @Html.HiddenFor(m => m.UserViewModels[i].Id)
                                        @Html.HiddenFor(m => m.UserViewModels[i].Email)
                                        @Model.UserViewModels[i].Email
                                    </td>
                                    <td>
                                        @for (int j = 0; j < Model.UserViewModels[i].RoleViewModels.Count; j++)
                                        {
                                            @Html.HiddenFor(m => m.UserViewModels[i].RoleViewModels[j].Id)
                                            @Html.HiddenFor(m => m.UserViewModels[i].RoleViewModels[j].Name)
                                            @Html.CheckBoxFor(m => m.UserViewModels[i].RoleViewModels[j].IsSelected)
                                            @Html.DisplayTextFor(m => m.UserViewModels[i].RoleViewModels[j].Name)
                                            <br/>
                                        }
                                    </td>
                                    <td>
                                        @Html.CheckBoxFor(m => m.UserViewModels[i].DeleteUser)
                                        @Html.DisplayNameFor(m => m.UserViewModels[i].DeleteUser)
                                    </td>
                                </tr>
                            }
                        </tbody>
                    </table>
                </div>

                @* Reset and Submit buttons *@
                <div class="col-lg-2 col-lg-push-8 col-md-2 col-md-push-8 col-sm-2 col-sm-push-8 col-xs-2 col-xs-push-8">
                    <input type="reset" class="btn btn-danger btn-block" value="Reset" />
                </div>
                <div class="col-lg-2 col-lg-push-8 col-md-2 col-md-push-8 col-sm-2 col-sm-push-8 col-xs-2 col-xs-push-8">
                    <input type="submit" class="btn btn-primary btn-block" value="Submit" />
                </div>

            </div>
        }
    </div>
</div>

现在更新用户的角色并删除它们(虽然没有确认检查所以要小心!)