Reputation: 1299
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.
Upvotes: 4
Views: 4416
Reputation: 61
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 );
}
}
Upvotes: 0
Reputation: 842
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:
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.
Upvotes: 3
Reputation: 145890
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.
Upvotes: 2
Reputation: 11323
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();
Upvotes: 5
Reputation: 5191
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.
Upvotes: 2