Strongly typed view with a SelectList for DropDownList via ViewData: type mismatch on submit

Cymen picture Cymen · Mar 2, 2010 · Viewed 7.3k times · Source

I am trying to create a form in ASP.NET MVC2 RC 2 that is based on a calendar event object. The object has eventTypeId which is a System.Int32 that I need to populate with via a select list.

The controller to create the initial view is:

[WAuthorize]
public ActionResult AddCalendarEvent()
{
    CalendarEventTypesManager calendarEventTypesManager = 
        new CalendarEventTypesManager();

    ViewData["eventTypeId"] = new SelectList(
        calendarEventTypesManager.SelectAll(), "Id", "Type");

    return View();
}

The snippet of the View (with the header) is:

<%@ Page Title="" Language="C#" 
    MasterPageFile="~/Views/Shared/Site.Extranet.master"
    Inherits="System.Web.Mvc.ViewPage<SomeProject.Models.CalendarEvent>" %>

...

<p><%= Html.DropDownList("eventTypeId") %></p>

Which results the HTML of:

<p>
<select id="eventTypeId" name="eventTypeId">
    <option value="1">All school activities</option> 
    <option value="2">All school event</option> 
</select>
</p> 

The POST-accepting controller is:

[WAuthorize]
// TODO research some more
[ValidateInput(false)]              
[AcceptVerbs(HttpVerbs.Post)]
[ValidateAntiForgeryToken]
public ActionResult AddCalendarEvent(CalendarEvent newEvent)
{
    ...

(I've tried adding [Bind (Exclude="eventTypeId")] in front of the "CalendarEvent newEvent" parameter but it does not change the behavior.)

Problem: When I submit the form, I get an InvalidOperationException exception:

The ViewData item that has the key 'eventTypeId' is of type 'System.Int32' but must be of type 'IEnumerable<SelectListItem>'.

I've looked at a number of examples here and on the MVC blogs but so far it isn't clear how this is supposed to work (it looks like based on many examples, it should work as is). Do I need to create a second model that has a variable of type SelectListItem to accept the SelectListItem and convert the value to a System.Int32 to actually set eventTypeId? That seems rather round about.

Answer

Cymen picture Cymen · Mar 2, 2010

After thinking about this some more, I thought that maybe I needed to populate ViewData["eventTypeID"] in the controller action that receives the posted values -- not just in the controller action that sets up the form. I tried that and it worked.

The controller action that accepts the POST was altered (adding the last two lines in this listing):

    [WAuthorize]
    [ValidateInput(false)]              // TODO research some more
    [AcceptVerbs(HttpVerbs.Post)]
    [ValidateAntiForgeryToken]
    public ActionResult AddCalendarEvent(CalendarEvent newEvent)
    {
        CalendarEventTypesManager calendarEventTypesManager = new CalendarEventTypesManager();
        ViewData["eventTypeId"] = new SelectList(calendarEventTypesManager.SelectAll(), "Id", "Type");
        ....

That was not clear to me so hopefully someone else finds this useful too. I checked the actual HTTP POST with LiveHTTPHeaders plugin for Firefox and indeed entryTypeID is posted as "...&entryTypeId=2&..." (I had selected the second item on the form before submitting) but do we reload the select list in the posted-to controller to do validation?