问题
I'm using MVC3 with razor and I wanna make a registration form where I can choose role with a dropdownlist.
I get the roles in the dropdown list and all that but when i click submit i get:
The ViewData
item that has the key 'Role' is of type System.String
but must be of type IEnumerable<SelectListItem>
.
My code
Model:
[Required]
[Display(Name = "Select role: ")]
public String Role { get; set; }
My controller:
public ActionResult Register()
{
List<SelectListItem> list = new List<SelectListItem>();
SelectListItem item;
foreach (String role in Roles.GetAllRoles())
{
item = new SelectListItem{ Text = role, Value = role};
list.Add(item);
}
ViewBag.roleList = (IEnumerable<SelectListItem>)list;
return View();
}
My post controller:
[HttpPost]
public ActionResult Register(RegisterModel model)
{
if (ModelState.IsValid)
{
// Attempt to register the user
MembershipCreateStatus createStatus;
Membership.CreateUser(model.UserName, model.Password, model.Email, null, null, true, null, out createStatus);
if (createStatus == MembershipCreateStatus.Success)
{
Roles.AddUserToRole(model.UserName, model.Role);
return RedirectToAction("Index", "Home");
}
else
{
ModelState.AddModelError("", ErrorCodeToString(createStatus));
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
My view:
<div class="editor-label">
@Html.LabelFor(m => m.Role)
</div>
<div class="editor-field">
@Html.DropDownListFor(m => m.Role, ViewBag.roleList as IEnumerable<SelectListItem>)
@Html.ValidationMessageFor(m => m.Role)
</div>
When I use the debugger to check my code, in the controller when I look on the parameter model and at model.Role
I see the right String.
Does anyone know any solution to my problem?
回答1:
In your POST action you are not repopulating the roleList
in the ViewBag
in the case when you redisplay the view:
...
// If we got this far, something failed, redisplay form
// but before redisplaying the form ensure that we have populated the
// ViewBag.roleList that this form depends on
ViewBag.roleList = ... same stuff as your GET action
return View(model);
This being said I would recommend you to get rid of ViewBag
and add the RoleList
property to your view model:
public class RegisterModel
{
[Required]
[Display(Name = "Select role: ")]
public string Role { get; set; }
public IEnumerable<SelectListItem> RoleList
{
get
{
return Roles
.GetAllRoles()
.Select(x => new SelectListItem
{
Value = x,
Text = x
})
.ToList();
}
}
}
and then:
public ActionResult Register()
{
var model = new RegisterModel();
return View(model);
}
[HttpPost]
public ActionResult Register(RegisterModel model)
{
if (ModelState.IsValid)
{
// Attempt to register the user
MembershipCreateStatus createStatus;
Membership.CreateUser(model.UserName, model.Password, model.Email, null, null, true, null, out createStatus);
if (createStatus == MembershipCreateStatus.Success)
{
Roles.AddUserToRole(model.UserName, model.Role);
return RedirectToAction("Index", "Home");
}
else
{
ModelState.AddModelError("", ErrorCodeToString(createStatus));
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
and in your strongly typed view:
@model RegisterModel
...
<div class="editor-label">
@Html.LabelFor(m => m.Role)
</div>
<div class="editor-field">
@Html.DropDownListFor(m => m.Role, Model.RoleList)
@Html.ValidationMessageFor(m => m.Role)
</div>
No more ViewBag => no problems.
来源:https://stackoverflow.com/questions/8741869/registration-form-with-roles-mvc3-error-viewdata-item-is-of-type-system-sting