删除DropDownList中的条目会导致"值不能为空。参数名称:items"

时间:2015-10-06 16:38:33

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

我有两种形式:一种用于为用户分配角色,另一种用于从用户中删除角色。他们的观点和控制者都非常相似。他们在这里(形式本身):

AssignRole.cshtml

            @using (Html.BeginForm("AssignRole", "User", new { ReturnUrl = ViewBag.ReturnUrl }, FormMethod.Post, new { @class = "form-horizontal", role = "form" }))
            {
                @Html.AntiForgeryToken()
                @Html.ValidationSummary(true, "", new { @class = "text-danger" })
                @Html.HiddenFor(m => m.UserID)
                <div class="form-group">
                    @Html.LabelFor(m => m.UserName, new { @class = "col-md-2 control-label" })
                    <div class="col-md-10">
                        @Html.TextBoxFor(m => m.UserName, new { @class = "form-control", @readonly = "readonly" })
                        @Html.ValidationMessageFor(m => m.UserName, "", new { @class = "text-danger" })
                    </div>
                </div>
                <div class="form-group">
                    @Html.LabelFor(m => m.RoleName, new { @class = "col-md-2 control-label" })
                    <div class="col-md-10">
                        @Html.DropDownListFor(m => m.RoleName, new SelectList(Model.UnassignedRoles, "Value", "Text"), Resources.DropdownSelect, new { @class = "form-control" })
                    </div>
                </div>
                <div class="form-group">
                    <div class="col-md-offset-2 col-md-10">
                        <input type="submit" value="@Resources.Assign" class="btn btn-default" />
                    </div>
                </div>
            }

RemoveRole.cshtml

            @using (Html.BeginForm("RemoveRole", "User", new { ReturnUrl = ViewBag.ReturnUrl }, FormMethod.Post, new { @class = "form-horizontal", role = "form" }))
            {
                @Html.AntiForgeryToken()
                @Html.ValidationSummary(true, "", new { @class = "text-danger" })
                @Html.HiddenFor(m => m.UserID)
                <div class="form-group">
                    @Html.LabelFor(m => m.UserName, new { @class = "col-md-2 control-label" })
                    <div class="col-md-10">
                        @Html.TextBoxFor(m => m.UserName, new { @class = "form-control", @readonly = "readonly" })
                        @Html.ValidationMessageFor(m => m.UserName, "", new { @class = "text-danger" })
                    </div>
                </div>
                <div class="form-group">
                    @Html.LabelFor(m => m.RoleName, new { @class = "col-md-2 control-label" })
                    <div class="col-md-10">
                        @Html.DropDownListFor(m => m.RoleName, new SelectList(Model.AssignedRoles, "Value", "Text"), Resources.DropdownSelect, new { @class = "form-control" })
                    </div>
                </div>
                <div class="form-group">
                    <div class="col-md-offset-2 col-md-10">
                        <input type="submit" value="@Resources.Remove" class="btn btn-default" />
                    </div>
                </div>
            }

最后,这里的控制器使用了他们使用的操作:

UserController.cs

        //
        // GET: /User/AssignRole
        [Authorize(Roles = "Admin")]
        [HttpGet]
        public ActionResult AssignRole(string userID)
        {
            var user = context.Users.Where(u => u.Id == userID).FirstOrDefault();
            var vm = new UserAssignRoleViewModel();
            vm.UserID = user.Id;
            vm.UserName = user.UserName;

            List<IdentityRole> unassignedRoles = new List<IdentityRole>();
            foreach (var role in context.Roles)
            {
                if (this.UserManager.IsInRole(vm.UserID, role.Name) == false)
                {
                    unassignedRoles.Add(role);
                }
            }
            vm.UnassignedRoles = unassignedRoles.OrderBy(r => r.Name).Select(rr => new SelectListItem { Value = rr.Name.ToString(), Text = rr.Name }).ToList();

            return View(vm);
        }

        //
        // POST: /User/AssignRole
        [Authorize(Roles = "Admin")]
        [HttpPost]
        public ActionResult AssignRole(UserAssignRoleViewModel vm)
        {
            this.UserManager.AddToRole(vm.UserID, vm.RoleName);
            ViewBag.ResultMessage = Resources.RoleAssignedSuccessfully;

            List<IdentityRole> unassignedRoles = new List<IdentityRole>();
            foreach (var role in context.Roles)
            {
                if (this.UserManager.IsInRole(vm.UserID, role.Name) == false)
                {
                    unassignedRoles.Add(role);
                }
            }
            vm.UnassignedRoles = unassignedRoles.OrderBy(r => r.Name).Select(rr => new SelectListItem { Value = rr.Name.ToString(), Text = rr.Name }).ToList();

            return View(vm);
        }

        //
        // GET: /User/RemoveRole
        [Authorize(Roles = "Admin")]
        [HttpGet]
        public ActionResult RemoveRole(string userID)
        {
            var user = context.Users.Where(u => u.Id == userID).FirstOrDefault();
            var vm = new UserRemoveRoleViewModel();
            vm.UserID = user.Id;
            vm.UserName = user.UserName;
            vm.AssignedRoles = context.Roles.OrderBy(r => r.Name).ToList().Select(rr => new SelectListItem { Value = rr.Name.ToString(), Text = rr.Name }).ToList();

            List<IdentityRole> assignedRoles = new List<IdentityRole>();
            foreach (var role in context.Roles)
            {
                if (this.UserManager.IsInRole(vm.UserID, role.Name) == true)
                {
                    assignedRoles.Add(role);
                }
            }
            vm.AssignedRoles = assignedRoles.OrderBy(r => r.Name).Select(rr => new SelectListItem { Value = rr.Name.ToString(), Text = rr.Name }).ToList();

            return View(vm);
        }

        //
        // POST: /User/RemoveRole
        [Authorize(Roles = "Admin")]
        [HttpPost]
        public ActionResult RemoveRole(UserRemoveRoleViewModel vm)
        {
            if (this.UserManager.IsInRole(vm.UserID, vm.RoleName))
            {
                this.UserManager.RemoveFromRole(vm.UserID, vm.RoleName);
                ViewBag.ResultMessage = Resources.RoleUnassignedSuccessfully;

                List<IdentityRole> assignedRoles = new List<IdentityRole>();
                foreach (var role in context.Roles)
                {
                    if (this.UserManager.IsInRole(vm.UserID, role.Name) == true)
                    {
                        assignedRoles.Add(role);
                    }
                }
            }
            else
            {
                ViewBag.ResultMessage = Resources.ThisUserDoesNotBelongToSelectedRole;
            }

            return View (vm);
        }

以下是问题:

下拉列表必须每次都重新填充,要么为用户分配角色,要么删除它们。在指派角色方面一切正常;它只显示下拉列表中未分配的角色,当您添加角色时,从POST操作返回时,它会显示刷新的下拉列表而不包含您刚刚分配的角色。

但是在删除角色方面,只要从用户中删除角色(它正确地执行),从POST操作返回到视图就会抛出异常

  

值不能为空。参数名称:items

@Html.DropDownListFor(m => m.RoleName, new SelectList(Model.AssignedRoles, "Value", "Text"), Resources.DropdownSelect, new { @class = "form-control" })

我的猜测是,因为在POST Action方法中RemoveRole我没有以任何方式更改RoleName的{​​{1}}属性,并返回到视图下拉列表已重新填充,UserRemoveRoleViewModel崩溃,因为它正在查找已删除的角色,该角色已不在列表中。希望我能够很好地解释自己。

问题是我完全不知道如何解决这个问题。有什么帮助吗?

3 个答案:

答案 0 :(得分:2)

看起来第二种方法,对于删除,缺少一行,它使用角色列表重新初始化模型对象。由于ASP.NET MVC是无状态的,因此即使返回的视图相同,也必须对每个请求进行重新初始化。

添加以下行:

vm.AssignedRoles = assignedRoles.OrderBy(r => r.Name).Select(rr => new SelectListItem { Value = rr.Name.ToString(), Text = rr.Name }).ToList();

在foreach结束于RemoveRole之后,错误应该消失。

答案 1 :(得分:0)

问题是您从未将assignedRoles集合分配给您的view属性(AssignedRoles)。

此外,您可以使用LINQ语句创建列表,从而使代码更清晰。

答案 2 :(得分:0)

在您的GET操作中,您填写视图模型的AssignedRoles属性。在POST操作中,您无法执行此操作。所以当它到达视图代码时它是null并且帮助器不能从空集合中创建一个下拉列表。您需要在POST操作中填充它。 (请注意,它不会在GET和POST操作之间保持填充。)