ASP.NET MVC UpdateModel empty property
Asked Answered
T

5

4

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.

Truculent answered 18/2, 2009 at 4:29 Comment(0)
N
5

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();
Nayarit answered 12/3, 2009 at 20:41 Comment(0)
P
3

This is kinda related and I thought it could help those who somehow reached this page. I am working with ASP.NET MVC 3 and in this version when an empty text box is posted to the server it's bound as null to the model.

I had to write the opposite model binder - one that changes null strings to empty strings.

I took the above code by Andrew Peters (thanks for that!) and changed it to the following.

Things to notice:

  1. As mentioned already - this model binder does the opposite.
  2. Instead of checking the type of the value I'm checking it via the propertyDescriptor, which I think is better, because this is it's purpose - to describe the value. In my case it's essential because I can't examine a value that's null. Through the descriptor I can find all that I need.

And here's code:

public sealed class CustomModelBinder : DefaultModelBinder
{
    protected override void SetProperty(ControllerContext controllerContext,
        ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor, object value)
    {
        if (value == null && propertyDescriptor.PropertyType == typeof(string))
            value = string.Empty;

        base.SetProperty(controllerContext, bindingContext, propertyDescriptor, value);
    }
}

I hope this helps someone.

Pitta answered 25/11, 2011 at 2:25 Comment(0)
Q
2

UpdateModel initialize a property when this property is in the FormCollection. In order to prevent UpdateModel from setting some properties to empty values you can delete all items from your FormCollection where value is empty. To do this you can add an extension method to the NameValueCollection type.

Quaker answered 18/2, 2009 at 5:8 Comment(2)
What if I edit an instance of B that already has InstanceOfA.Name set? I'm assuming it will keep the original value.Truculent
If you'll not delete text from "Html.TextBox("A.Name")" it will be posted. If instance of B has instance of A with empty name then textbox will be empty and as a result this item will be removed during post and the value will not change to null.Quaker
M
2

It appears that ASP.NET MVC 2 Preview 1 will do this for you when doing modelbinding.

ie. convert automatically ?Foo=&Bar=cat to

model.Foo = null;
model.Bar = "cat":

I actually prefer to get an empty string over a null so I'm not sure yet if its the final design but there does seem to be a change.

Molding answered 11/8, 2009 at 23:37 Comment(0)
T
0

Thanks for your answer, I changed it a little bit so that not all string properties are changed, and properties that are not string can be changed too. Thanks to DefaultValueAttribute.

public class DefaultValueModelBinder: DefaultModelBinder
{
  protected override void SetProperty( ControllerContext controllerContext,
                                       ModelBindingContext bindingContext,
                                       PropertyDescriptor propertyDescriptor, 
                                       object value )
  {
    if( value == null )
    {
      var defaultValue = (DefaultValueAttribute)propertyDescriptor.Attributes[ typeof(DefaultValueAttribute) ];
      if( defaultValue != null )
        value = defaultValue.Value;
    }

    base.SetProperty( controllerContext, bindingContext, propertyDescriptor, value );
  }
}
Thierry answered 29/1, 2013 at 15:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.