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 的方法。这不是很容易维护和明显的,所以我建议你只坚持模型方法。这应该不是很难 - 添加角色名称列表作为模型的 属性,并确保在每次请求时对其进行初始化。