ASP.NET MVC 2.0 Undocumented Model String Property Binding Breaking Change

The default behavior of Model binding in ASP.NET MVC 1.0 was to initialize strings to string.Empty. However, MVC 2.0 defaults to initializing strings to null. Unfortunately, this is not listed as one of the breaking changes from MVC 1.0.

This can be a big problem if you have a substantial site built in MVC 1.0 and you import it into Visual Studio 2010 and use MVC 2.0. You may find that you are suddenly throwing NullReferenceException during model binding on code that is working in production.

Locating the Issue

ASP.NET MVC source code is available under the Ms-PL open source license which means that it is possible to diff the two versions of MVC and figure out what changed without having to guess or disassemble anything.

DefaultModelBinder-diff

protected virtual object GetPropertyValue(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor, IModelBinder propertyBinder) {
    object value = propertyBinder.BindModel(controllerContext, bindingContext);

    if (bindingContext.ModelMetadata.ConvertEmptyStringToNull && Object.Equals(value, String.Empty)) {
        return null;
    }

    return value;
}

MVC 2.0 adds some indirection to the binding behavior of the DefaultModelBinder class via a new ModelMetadata class which governs some of the behavior of DefaultModelBinder. Of particular interest here is that there is a property named ConvertEmptyStringToNull which, when true, causes an empty string to be returned as null instead.

It also turns out that when ModelMetaData is constructed, the value of ConvertEmptyStringToNull is set to true and there is no code in MVC which changes that default value.

ModelMetaData.ConvertEmptyString-default

Restoring MVC 1.0 Model String Property Binding Behavior

I think the quickest solution is going to be to set that ConvertEmptyStringToNull property to false by providing a creating a new, custom default implementation of IModelBinder by inheriting from DefaultModelBinder and changing the ConvertEmptyStringToNull value to false on the internal ModelMetaData object.

public sealed class EmptyStringModelBinder : DefaultModelBinder 
{
    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        bindingContext.ModelMetadata.ConvertEmptyStringToNull = false;
        return base.BindModel(controllerContext, bindingContext);
    }
}

Then the Application_Start() method of Global.asax.cs, we set the DefaultBinder property of ModelBinderDictionary to use our custom type instead of leaving it as the default. This is exposed through the Binders property on the static ModelBinders class so that we get our IModelBinder as the default instead of DefaultModelBinder.

protected void Application_Start()
{
	ModelBinders.Binders.DefaultBinder = new EmptyStringModelBinder();
	RegisterRoutes( RouteTable.Routes );
}
Advertisement

4 Responses to ASP.NET MVC 2.0 Undocumented Model String Property Binding Breaking Change

  1. Alex says:

    Don’t work for such types

    public partial class BilingualString
    {
    public string RuString { get; set; }
    public string EnString { get; set; }
    }

    public partial class Member
    {
    public Member()
    {
    this.DisplayName = new BilingualString();
    }
    public BilingualString DisplayName { get; set; }
    }

  2. Pingback: MVC.NET 2 Breaking Changes – Simon Dean’s Blog

  3. Pingback: [Gist] ASP.NET MVC bind String property as string.Empty instead of null » Johannes' Blog

  4. Pingback: Dynamics GP Land

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: