MVC Beta to RTW upgrade issue – AddModelError and NullReferenceExceptions

Since we use quite a lot of the MVC extension points on our current project, we knew that we’d suffer some upgrade pains going from release to release of MVC.  This isn’t that new for us, as we use a variety of open source projects.  But for a Beta product, it’s almost guaranteed that you’ll run into some issues with upgrades.

Our upgrade has been…less than fun.  Besides the heinous Visual Studio crashing issues, we were bitten by a wide variety of API changes.  One in particular gave me the fits for about two weeks, a multi-headed hydra that I couldn’t quite fix.

In our applications, we use ModelState errors to bubble up validation errors to the UI.  Most of these aren’t manually pushed in, but rather done through model binding.  We use a variety of validation in our application, including Castle Validators, as well as custom business rules that still bubble up to the UI.  From “Start Date is required” to “Start Date cannot be a future date” to “Start Date cannot come before the first contract start date”.

We hid all this behind a few classes, but at some point, we had to add something like this:

public void SomeAction()
    ModelState.AddModelError("SomeKey", "I am a required field.");

Very innocuous.  We had a required field, it wasn’t submitted as part of the form (and didn’t even come across the request), and we added a model error.  The problem shows it ugly head if you try and use MVC’s built-in HtmlHelper to generate HTML.  Its input element generators are “aware” of ModelState and ViewState, and will try and use these pieces to do things like populate the value of an HTML element.  What we wound up getting was an error something like this:

[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.InputExtensions.InputHelper(HtmlHelper htmlHelper, InputType inputType, String name, Object value, Boolean useViewData, Boolean isChecked, Boolean setId, Boolean isExplicitValue, IDictionary`2 htmlAttributes) +519
   System.Web.Mvc.Html.InputExtensions.TextBox(HtmlHelper htmlHelper, String name, Object value, IDictionary`2 htmlAttributes) +34
   System.Web.Mvc.Html.InputExtensions.TextBox(HtmlHelper htmlHelper, String name, Object value) +61

The fix wound up being for us to create a “SafeAddModelError” extension method.  The HtmlHelpers expect some ModelState ValueProviderResult to exist, but it doesn’t because we do our own custom validation.  Long, long story short, here was our fix:

public static void SafeAddModelError(this ModelStateDictionary state, string key, string errorMessage)
    state.AddModelError(key, errorMessage);
    if (state[key].Value == null)
        state[key].Value = new ValueProviderResult(null, null, null);

I have no idea if this error helps anyone but me, but hey, I enjoy sharing my pain.

About Jimmy Bogard

I'm a technical architect with Headspring in Austin, TX. I focus on DDD, distributed systems, and any other acronym-centric design/architecture/methodology. I created AutoMapper and am a co-author of the ASP.NET MVC in Action books.
This entry was posted in ASPNETMVC. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • Jimmy,
    At first glance it seems like this might actually be a bug (where bug could be defined as behavior which breaks the “rule of least surprise”) in mvc, yes? Or is it just simply a side effect of the way your populating/handling error states?

    Either way, it seems like something that might come up often enough to warrant some attention & possibly a fix within the mvc framework. Should we get Phil on the phone? :)

  • Jason Dentler

    Thanks for that fix Jimmy! I had the same issue with DropDownList. For me specifically, a required drop down list was hidden with jQuery before the form was submitted, so it didn’t post a value. The value never made it to the model state. When I added an error saying the field was required, the HtmlHelper assumed it would have a value just because the key existed in the model state dictionary.

  • Greg McNamara

    Thanks for that workaround Jimmy! Probably saved me hours of time and some of my hair! I’m overriding the DefaultModelBinder which was affecting the ModelState and causing a NullReferenceException on my dropdown list.

  • Scott

    Top Jimmy, he’s the king!

  • pikesville Paesano

    Thanks! you saved me a few aspirin!

  • Arjen de Mooij

    Thx, mate, had exactly the same problem

  • Just ran into this very same problem. Very, very odd behavior on MVC’s part. (BTW, my shot-in-the-dark Google search for this problem was “addmodelerror value null”, which led me to this post.)

  • Man

    Thank you very much! You’re the boss!

  • Sean Yang

    Thank you very much. It works well. Cool!