ASP.NET MVC Validation throws NullReferenceException against empty listbox

asp.net-mvc, listbox, validation

Solution

See the release notes for ASP.NET MVC 2 Preview 1; apparently this (NullReferenceException when passing null into model state) is a know bug in ASP.NET MVC.

Problem

I have two listboxes, one for available servers and one for selected servers. A user moves items from the first box to the second to indicate their selection. ``` <table id="ServerLists" style="width: 100%;"> <tr> <td style="width: 40%;"> <%=Html.ListBox("AvailableServerList", Model.AvailableServerList, New With {.size = 8, .ondblclick = "addServer();"})%> </td> <td style="width: 20%;"> <button type="button" onclick="addAll();">Add All &gt;&gt;</button> <button type="button" onclick="addServer();">Add &gt;</button> <button type="button" onclick="removeServer();">&lt; Remove</button> <button type="button" onclick="removeAll();">&lt;&lt; Remove All</button> </td> <td style="width: 40%;"> <%=Html.ListBox("SelectedServerList", Model.SelectedServerList, New With {.size = 8, .ondblclick = "removeServer();"})%> </td> </tr> </table> ``` If no servers are added to the second listbox I add an error to the ModelState. The problem is that if there are no entries in the listbox MVC throws a NullReferenceException when rendering the view with the validation warnings. ``` [NullReferenceException: Object reference not set to an instance of an object.] System.Web.Mvc.HtmlHelper.GetModelStateValue(String key, Type destinationType) +63 System.Web.Mvc.Html.SelectExtensions.SelectInternal(HtmlHelper htmlHelper, String optionLabel, String name, IEnumerable`1 selectList, Boolean allowMultiple, IDictionary`2 htmlAttributes) +155 System.Web.Mvc.Html.SelectExtensions.ListBox(HtmlHelper htmlHelper, String name, IEnumerable`1 selectList, Object htmlAttributes) +62 ASP.views_serveraccess_create_aspx.__RendercMain(HtmlTextWriter __w, Control parameterContainer) in C:\Documents and Settings\nfoster\My Documents\Visual Studio Projects\Client Portal 3\Trunk\src\Stargate3.Web\Views\ServerAccess\Create.aspx:148 System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children) +256 System.Web.UI.Control.RenderChildren(HtmlTextWriter writer) +19 System.Web.UI.Control.Render(HtmlTextWriter writer) +10 System.Web.UI.Control.RenderControlInternal(HtmlTextWriter writer, ControlAdapter adapter) +27 System.Web.UI.Control.RenderControl(HtmlTextWriter writer, ControlAdapter adapter) +99 System.Web.UI.Control.RenderControl(HtmlTextWriter writer) +25 System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children) +134 System.Web.UI.Control.RenderChildren(HtmlTextWriter writer) +19 System.Web.UI.Control.Render(HtmlTextWriter writer) +10 System.Web.UI.Control.RenderControlInternal(HtmlTextWriter writer, ControlAdapter adapter) +27 System.Web.UI.Control.RenderControl(HtmlTextWriter writer, ControlAdapter adapter) +99 System.Web.UI.Control.RenderControl(HtmlTextWriter writer) +25 ASP.views_shared_site_master.__Render__control1(HtmlTextWriter __w, Control parameterContainer) in C:\Documents and Settings\nfoster\My Documents\Visual Studio Projects\Client Portal 3\Trunk\src\Stargate3.Web\Views\Shared\Site.Master:97 System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children) +256 System.Web.UI.Control.RenderChildren(HtmlTextWriter writer) +19 System.Web.UI.Control.Render(HtmlTextWriter writer) +10 System.Web.UI.Control.RenderControlInternal(HtmlTextWriter writer, ControlAdapter adapter) +27 System.Web.UI.Control.RenderControl(HtmlTextWriter writer, ControlAdapter adapter) +99 System.Web.UI.Control.RenderControl(HtmlTextWriter writer) +25 System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children) +134 System.Web.UI.Control.RenderChildren(HtmlTextWriter writer) +19 System.Web.UI.Control.Render(HtmlTextWriter writer) +10 System.Web.UI.Control.RenderControlInternal(HtmlTextWriter writer, ControlAdapter adapter) +27 System.Web.UI.Control.RenderControl(HtmlTextWriter writer, ControlAdapter adapter) +99 System.Web.UI.Control.RenderControl(HtmlTextWriter writer) +25 System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children) +134 System.Web.UI.Control.RenderChildren(HtmlTextWriter writer) +19 System.Web.UI.Page.Render(HtmlTextWriter writer) +29 System.Web.Mvc.ViewPage.Render(HtmlTextWriter writer) +57 System.Web.UI.Control.RenderControlInternal(HtmlTextWriter writer, ControlAdapter adapter) +27 System.Web.UI.Control.RenderControl(HtmlTextWriter writer, ControlAdapter adapter) +99 System.Web.UI.Control.RenderControl(HtmlTextWriter writer) +25 System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +1266 ``` Has anyone else had this issue? Are there any workarounds I can try? I'm probably going to have to insert a [please select a server] entry in there if no choices have been made, but a fix for this problem would be appreciated. EDIT: Added controller action as requested ``` <AcceptVerbs(HttpVerbs.Post)> _ Function Create(ByVal collection As FormCollection) As ActionResult Dim acceptedFields() As String = {"StartTime", "EndTime", "ReasonForAccess", "WorkToBeDone", "RegressionPlan", "Servers", "AccessAccount", "Password"} Dim accessRequest As New ServerAccessRequest UpdateModel(Of ServerAccessRequest)(accessRequest, acceptedFields) If accessRequest.IsValid Then 'TODO: Do database stuff here Return View("AccessRequestConfirmation") Else For Each violation In accessRequest.GetRuleViolations ModelState.AddModelError(violation.PropertyName, violation.ErrorMessage) Next End If Return View(New ServerAccessViewModel(accessRequest)) End Function ```

Original source