Search code examples
asp.net-mvcmodelbinders

ASP.NET MVC UpdateModel empty property


Given the following Model,

public class A
{
    public string Name { get; set; }
}

public class B
{
    public string Address { get; set; }
    public A InstanceOfA { get; set; }
}

View,

<%= Html.TextBox("A.Name") %>

and Controller

UpdateModel<B>(b, collection.ToValueProvider());

my b instance will contain a property of A with an empty string for Name.

Is there anyway to have UpdateModel set the A property to null if no value has been entered for name?

To clarify, this is a simple case, my real world scenario contains data models with hundreds of properties of this ilk. The definition of these data models is out of my hands. Therefore I need a solution for the general case, ie don't create a property if no values have been entered.

Further clarification: i need this to work in edit scenarios aswell, i.e. an instance of b with A.Name set to "foo" is edited to set A.Name to "", i want A to be null.


Solution

  • I just discovered this behavior (by accident thanks to a check constraint) and I think it is a mistake. I wonder how many devs are now inadvertently saving empty strings into their db instead of null? :-)

    Anyway, I'm going to explore this a bit more and see if there is a better solution.

    Update:

    Here is a solution:

    using System.ComponentModel;
    using System.Web.Mvc;
    
    namespace CustomerWebsite.Mvc
    {
      public sealed class EmptyStringToNullModelBinder : DefaultModelBinder
      {
        protected override void SetProperty(ControllerContext controllerContext,
          ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor, object value)
        {
          if ((value != null)
              && (value.GetType() == typeof(string)
                  && ((string)value).Length == 0))
          {
            value = null;
          }
    
          base.SetProperty(controllerContext, bindingContext, propertyDescriptor, value);
        }
      }
    }
    

    And in Application_Start put this:

    ModelBinders.Binders.DefaultBinder = new EmptyStringToNullModelBinder();