ASP.NET MVC 5 中简单成员的 IEnumerable<SelectListItem> 错误
IEnumerable<SelectListItem> error in Simple Membership in ASP.NET MVC 5
我在 ASP.NET MVC 5 中使用简单成员资格来使用我现有的 SQL 服务器。在注册页面中,我使用下拉框来填充用户角色。在我的帐户控制器中,我使用 [HttpGet] 和 [HttpPost] 进行注册操作。当我 运行 我的网络应用程序并转到注册页面时,我可以看到我的 DropDownBox 填充了来自我的 SqlServer 的数据。
但是,当我尝试创建新用户和 select 角色时,我收到错误消息;
"不存在具有键 'roleName'"
的 'IEnumerable' 类型的 ViewData 项
这是我的帐户控制器代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using SimpleMemberShip.Models;
using WebMatrix.WebData;
using System.Web.Security;
namespace SimpleMemberShip.Controllers
{
public class AccountController : Controller
{
// ****** REGISTER PAGE ACTION ******
[HttpGet]
public ActionResult Register()
{
//Roles for DropDown Box
IEnumerable<SelectListItem> RolesList = new System.Web.Mvc.SelectList(System.Web.Security.Roles.GetAllRoles(), "roleName");
ViewData["roleName"] = RolesList;
return View();
}
// ****** REGISTER PAGE ACTION with PARAMETERS ******
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Register(Register registerdata, string RoleName)
{
if (ModelState.IsValid)
{
try
{
WebSecurity.CreateUserAndAccount(registerdata.Username, registerdata.Password);
System.Web.Security.Roles.AddUserToRole(registerdata.Username, RoleName);
return RedirectToAction("Index", "Home");
}
catch (MembershipCreateUserException exception)
{
ModelState.AddModelError("", "Warning: Username exist...");
return View(registerdata);
}
}
ModelState.AddModelError("", "Warning: Username exist....");
return View(registerdata);
}
}
}
这是我的 Register.cshtml 代码 看起来像:
@using SimpleMemberShip.Models
@model Register
@{
ViewBag.Title = "Register";
}
<h2>New User Registration</h2>
<br />
<div>
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
@Html.ValidationSummary()
<label>User Name:</label>
@Html.TextBoxFor(m => m.Username, new { @class = "form-control" })
<br />
<label>User Password:</label>
@Html.PasswordFor(m => m.Password, new { @class = "form-control" })
<br />
<label>Roles</label>
@Html.DropDownList("roleName", (System.Web.Mvc.SelectList)ViewBag.roleName, "Select a Role")
<br />
<br />
<button class="btn btn-primary">Register</button>
}
</div>
有谁知道我哪里出错了?
亲切的问候,
在您的 HttpPost 操作中,如果发生某些错误,或者如果您的模型验证失败,则您正在 return 将相同的模型连接到相同的视图。因此,您需要再次使用角色列表集合重新加载 ViewData["roleName"]
,因为您的视图试图从中读取以加载下拉列表。
记住,HTTP 是无状态的。 ASP.NET MVC 不像 Web 表单那样工作,它在多个 http 请求(表单 posts)中以视图状态存储表单数据
我的建议是不要使用 ViewBag 和 ViewData 等动态内容。您应该使用强类型视图模型将数据从操作方法传输到视图。
所以创建一个像
这样的视图模型
public class CreateUser
{
public string UserName {set;get;}
public string Password{set;get;}
public List<SelectListItem> RolesList {set;get;}
public int SelectedRoleId {set;get;}
}
并且在您的 GET 操作方法中,您获得了所有角色(可以是 Role class 或一些自定义 class 的集合),将其转换为 SelectListItem
并将其分配给 CreateUser 对象
的 RolesList
属性
public ActionResult Register()
{
var vm=new CreateUser();
vm.RolesList =GetRoles();
return View(vm);
}
private List<SelectListItem> GetRoles()
{
var allRoles = System.Web.Security.Roles.GetAllRoles();
return allRoles.Select(s => new SelectListItem
{
Value = s.roleId.ToString(),
Text = s.roleName
});
}
并且在您绑定到 CreateUser
class.
的剃刀视图中
@using YourNamespace.CreateUser
@using(Html.Beginform())
{
@Html.TextBoxFor(s=>s.UserName)
@Html.TextBoxFor(s=>s.Password)
@Html.DropDownListFor(x=> x.SelectedRoleId, Model.RolesList,"Select")
<input type="submit" />
}
现在在您的 Http post 操作方法中,确保在 return 将 posted 模型返回到同一视图之前重新加载 RolesList
集合(如果模式验证失败或发生异常)
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Register(CreateUser model)
{
if (ModelState.IsValid)
{
try
{
// to do : Save something
// read model.UserName & model.SelectedRoleId etc.
return RedirectToAction("Index", "Home");
}
catch (MembershipCreateUserException exception)
{
ModelState.AddModelError("", "Warning: Username exist...");
//Reload the data now
model.RolesList =GetRoles();
return View(model);
}
}
ModelState.AddModelError("", "Warning: Username exist....");
//Reload the data now
model.RolesList =GetRoles();
return View(model);
}
最有可能发生的情况是您在注册用户的过程中出现某种错误,导致验证失败。在那种情况下,您将返回相同的视图,这很好:
return View(registerdata);
但是您没有重新填充视图所依赖的 ViewData["roleName"]
元素。由于 ASP.NET MVC 不维护任何类型的状态,因此需要在每次请求时重新填充此元素。因此,请考虑这样做,与之前在 GET 操作中所做的完全相同,错误应该会消失。
附带说明一下,您混合了两种将数据从控制器传递到视图、模型和 ViewData 的方法。这不是很容易维护和明显的,所以我建议你只坚持模型方法。这应该不是很难 - 添加角色名称列表作为模型的 属性,并确保在每次请求时对其进行初始化。
我在 ASP.NET MVC 5 中使用简单成员资格来使用我现有的 SQL 服务器。在注册页面中,我使用下拉框来填充用户角色。在我的帐户控制器中,我使用 [HttpGet] 和 [HttpPost] 进行注册操作。当我 运行 我的网络应用程序并转到注册页面时,我可以看到我的 DropDownBox 填充了来自我的 SqlServer 的数据。
但是,当我尝试创建新用户和 select 角色时,我收到错误消息;
"不存在具有键 'roleName'"
的 'IEnumerable' 类型的 ViewData 项这是我的帐户控制器代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using SimpleMemberShip.Models;
using WebMatrix.WebData;
using System.Web.Security;
namespace SimpleMemberShip.Controllers
{
public class AccountController : Controller
{
// ****** REGISTER PAGE ACTION ******
[HttpGet]
public ActionResult Register()
{
//Roles for DropDown Box
IEnumerable<SelectListItem> RolesList = new System.Web.Mvc.SelectList(System.Web.Security.Roles.GetAllRoles(), "roleName");
ViewData["roleName"] = RolesList;
return View();
}
// ****** REGISTER PAGE ACTION with PARAMETERS ******
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Register(Register registerdata, string RoleName)
{
if (ModelState.IsValid)
{
try
{
WebSecurity.CreateUserAndAccount(registerdata.Username, registerdata.Password);
System.Web.Security.Roles.AddUserToRole(registerdata.Username, RoleName);
return RedirectToAction("Index", "Home");
}
catch (MembershipCreateUserException exception)
{
ModelState.AddModelError("", "Warning: Username exist...");
return View(registerdata);
}
}
ModelState.AddModelError("", "Warning: Username exist....");
return View(registerdata);
}
}
}
这是我的 Register.cshtml 代码 看起来像:
@using SimpleMemberShip.Models
@model Register
@{
ViewBag.Title = "Register";
}
<h2>New User Registration</h2>
<br />
<div>
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
@Html.ValidationSummary()
<label>User Name:</label>
@Html.TextBoxFor(m => m.Username, new { @class = "form-control" })
<br />
<label>User Password:</label>
@Html.PasswordFor(m => m.Password, new { @class = "form-control" })
<br />
<label>Roles</label>
@Html.DropDownList("roleName", (System.Web.Mvc.SelectList)ViewBag.roleName, "Select a Role")
<br />
<br />
<button class="btn btn-primary">Register</button>
}
</div>
有谁知道我哪里出错了?
亲切的问候,
在您的 HttpPost 操作中,如果发生某些错误,或者如果您的模型验证失败,则您正在 return 将相同的模型连接到相同的视图。因此,您需要再次使用角色列表集合重新加载 ViewData["roleName"]
,因为您的视图试图从中读取以加载下拉列表。
记住,HTTP 是无状态的。 ASP.NET MVC 不像 Web 表单那样工作,它在多个 http 请求(表单 posts)中以视图状态存储表单数据
我的建议是不要使用 ViewBag 和 ViewData 等动态内容。您应该使用强类型视图模型将数据从操作方法传输到视图。
所以创建一个像
这样的视图模型public class CreateUser
{
public string UserName {set;get;}
public string Password{set;get;}
public List<SelectListItem> RolesList {set;get;}
public int SelectedRoleId {set;get;}
}
并且在您的 GET 操作方法中,您获得了所有角色(可以是 Role class 或一些自定义 class 的集合),将其转换为 SelectListItem
并将其分配给 CreateUser 对象
RolesList
属性
public ActionResult Register()
{
var vm=new CreateUser();
vm.RolesList =GetRoles();
return View(vm);
}
private List<SelectListItem> GetRoles()
{
var allRoles = System.Web.Security.Roles.GetAllRoles();
return allRoles.Select(s => new SelectListItem
{
Value = s.roleId.ToString(),
Text = s.roleName
});
}
并且在您绑定到 CreateUser
class.
@using YourNamespace.CreateUser
@using(Html.Beginform())
{
@Html.TextBoxFor(s=>s.UserName)
@Html.TextBoxFor(s=>s.Password)
@Html.DropDownListFor(x=> x.SelectedRoleId, Model.RolesList,"Select")
<input type="submit" />
}
现在在您的 Http post 操作方法中,确保在 return 将 posted 模型返回到同一视图之前重新加载 RolesList
集合(如果模式验证失败或发生异常)
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Register(CreateUser model)
{
if (ModelState.IsValid)
{
try
{
// to do : Save something
// read model.UserName & model.SelectedRoleId etc.
return RedirectToAction("Index", "Home");
}
catch (MembershipCreateUserException exception)
{
ModelState.AddModelError("", "Warning: Username exist...");
//Reload the data now
model.RolesList =GetRoles();
return View(model);
}
}
ModelState.AddModelError("", "Warning: Username exist....");
//Reload the data now
model.RolesList =GetRoles();
return View(model);
}
最有可能发生的情况是您在注册用户的过程中出现某种错误,导致验证失败。在那种情况下,您将返回相同的视图,这很好:
return View(registerdata);
但是您没有重新填充视图所依赖的 ViewData["roleName"]
元素。由于 ASP.NET MVC 不维护任何类型的状态,因此需要在每次请求时重新填充此元素。因此,请考虑这样做,与之前在 GET 操作中所做的完全相同,错误应该会消失。
附带说明一下,您混合了两种将数据从控制器传递到视图、模型和 ViewData 的方法。这不是很容易维护和明显的,所以我建议你只坚持模型方法。这应该不是很难 - 添加角色名称列表作为模型的 属性,并确保在每次请求时对其进行初始化。