Registration form with roles MVC3, Error: ViewData

2019-09-16 19:05发布

问题:

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.