删除 DropDownList 中的条目会导致 "Value cannot be null. Parameter name: items"
Deleting entries in DropDownList causes "Value cannot be null. Parameter name: items"
我有两种形式:一种用于为用户分配角色,另一种用于删除用户的角色。它们惊人地相似,无论是视图还是控制器。它们在这里(表格本身):
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 操作返回到视图它就会抛出异常
Value cannot be null. Parameter name: items
行
@Html.DropDownListFor(m => m.RoleName, new SelectList(Model.AssignedRoles, "Value", "Text"), Resources.DropdownSelect, new { @class = "form-control" })
我的猜测是,因为在 POST 操作方法 RemoveRole
中,我不会以任何方式更改 UserRemoveRoleViewModel
的 RoleName
属性 ,然后返回到已重新填充下拉列表的视图,m => m.RoleName
崩溃,因为它正在寻找已删除的角色,该角色不再在列表中。希望我能很好地解释自己。
问题是我完全不知道如何解决这个问题。有帮助吗?
问题是您从未将 assignedRoles 集合分配给您的视图 属性 (AssignedRoles)。
此外,您可以通过使用 LINQ 语句创建列表来使代码更简洁。
在您的 GET 操作中,您填写了视图模型的 AssignedRoles 属性。在 POST 操作中,您没有做到这一点。因此,当它到达视图代码时它是空的,并且助手无法从空集合中创建下拉列表。您需要在 POST 操作中填充它。 (请注意,它不会在 GET 和 POST 操作之间保持填充。)
看起来第二种删除方法缺少一行,该行使用角色列表重新初始化模型对象。由于 ASP.NET MVC 是无状态的,因此必须对每个请求进行重新初始化,即使返回的视图相同。
添加这一行:
vm.AssignedRoles = assignedRoles.OrderBy(r => r.Name).Select(rr => new SelectListItem { Value = rr.Name.ToString(), Text = rr.Name }).ToList();
在 foreach 结束后立即 RemoveRole
并且错误应该消失。
我有两种形式:一种用于为用户分配角色,另一种用于删除用户的角色。它们惊人地相似,无论是视图还是控制器。它们在这里(表格本身):
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 操作返回到视图它就会抛出异常
Value cannot be null. Parameter name: items
行
@Html.DropDownListFor(m => m.RoleName, new SelectList(Model.AssignedRoles, "Value", "Text"), Resources.DropdownSelect, new { @class = "form-control" })
我的猜测是,因为在 POST 操作方法 RemoveRole
中,我不会以任何方式更改 UserRemoveRoleViewModel
的 RoleName
属性 ,然后返回到已重新填充下拉列表的视图,m => m.RoleName
崩溃,因为它正在寻找已删除的角色,该角色不再在列表中。希望我能很好地解释自己。
问题是我完全不知道如何解决这个问题。有帮助吗?
问题是您从未将 assignedRoles 集合分配给您的视图 属性 (AssignedRoles)。
此外,您可以通过使用 LINQ 语句创建列表来使代码更简洁。
在您的 GET 操作中,您填写了视图模型的 AssignedRoles 属性。在 POST 操作中,您没有做到这一点。因此,当它到达视图代码时它是空的,并且助手无法从空集合中创建下拉列表。您需要在 POST 操作中填充它。 (请注意,它不会在 GET 和 POST 操作之间保持填充。)
看起来第二种删除方法缺少一行,该行使用角色列表重新初始化模型对象。由于 ASP.NET MVC 是无状态的,因此必须对每个请求进行重新初始化,即使返回的视图相同。
添加这一行:
vm.AssignedRoles = assignedRoles.OrderBy(r => r.Name).Select(rr => new SelectListItem { Value = rr.Name.ToString(), Text = rr.Name }).ToList();
在 foreach 结束后立即 RemoveRole
并且错误应该消失。