2

I have the following:

This action:

public virtual ActionResult Search(string search, string sort)
{
...
}

Called from this url with empty query string parameters:

http://myurl.com/mycontroller/search?search=&sort=

Now my understanding was that as of MVC 2 the DefaultModelBinder would leave these values as nulls. However, what I am finding is that they are actually set to empty strings. Is this in fact the expected behavior? Is this documented anywhere?

Thanks

gdoron
  • 147,333
  • 58
  • 291
  • 367
tribus
  • 1,110
  • 1
  • 9
  • 27

3 Answers3

6

Yes, The defualt behavior is setting empty strings to null, but it can be overriden with changing ConvertEmptyStringToNull = false;

true if empty strings that are posted back in forms should be converted to null;
otherwise, false. The default value is true.

msdn

like in this code:

public class SimpleArrayModelBinder : DefaultModelBinder 
{
    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) 
    {
        if (bindingContext.ModelType == typeof(string)) 
        {
            var value = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
            bindingContext.ModelMetadata.ConvertEmptyStringToNull = false;
            if (value == null || value.AttemptedValue.IsNullOrEmpty())
                return "";
            else
                return value.AttemptedValue;
        }
    }
}

One more way to change the deafult behavior is with the ConvertEmptyStringToNull attribute above the properties in your model.

Example:

public class Person
{
    [DisplayFormat(ConvertEmptyStringToNull = false)]
    public string Lastname { get; set; }
    ...
}

Blog

gdoron
  • 147,333
  • 58
  • 291
  • 367
  • OK I think this is where I'm getting lost. The documentation here http://msdn.microsoft.com/en-us/library/system.web.mvc.modelmetadata.convertemptystringtonull.aspx says that these empty strings are converted to null. What am I missing? – tribus Jun 13 '12 at 21:17
  • I've read this sevarl times but maybe I'm just misinterpreting it. It says "true if empty strings that are posted back in forms should be converted to null;" I read that as passing true (which is the default) will convert empty strings to null, not the other way around. – tribus Jun 13 '12 at 21:35
  • 1
    I'm seeing that this doesn't apply when your action expects a simple type. – tribus Jun 14 '12 at 12:45
  • @tribus. What do you mwan by "this doesn't apply"? – gdoron Jun 14 '12 at 13:21
  • The default behavior of setting empty strings to null seems to only apply when the model is a complex type. For simple types the ModelMetadata.ConvertEmptyStringToNull property is never checked. – tribus Jun 14 '12 at 13:34
  • @tribus. That is against MSDN, and what I found in the internet, weird. – gdoron Jun 14 '12 at 13:35
1

After looking through the source code for the DefaultModelBinder what I have found is that the ModelMetadata.ConvertEmptyStringToNull property is only ever checked when the model being bound is a complex model. For primative types exposed in an action, the values are retrieved as is. For the example in my original question, this would be an empty string.

From the DefaultModelBinder source

        // Simple model = int, string, etc.; determined by calling TypeConverter.CanConvertFrom(typeof(string))
        // or by seeing if a value in the request exactly matches the name of the model we're binding.
        // Complex type = everything else.
        if (!performedFallback) {
            bool performRequestValidation = ShouldPerformRequestValidation(controllerContext, bindingContext);
            ValueProviderResult vpResult = bindingContext.UnvalidatedValueProvider.GetValue(bindingContext.ModelName, skipValidation: !performRequestValidation);
            if (vpResult != null) {
                return BindSimpleModel(controllerContext, bindingContext, vpResult);
            }
        }
        if (!bindingContext.ModelMetadata.IsComplexType) {
            return null;
        }

        return BindComplexModel(controllerContext, bindingContext);
    }

So as far as I can tell ModelMetadata.ConvertEmptyStringToNull only applies when bindng a complex type.

tribus
  • 1,110
  • 1
  • 9
  • 27
0

ModelMetadata.ConvertEmptyStringToNull this property will affect when binding the values to strings that sits as properties inside a Model.

Ex.

public class Employee
{
   public string First{get;set;}
   public string Last{get;set;}
}

With ModelMetadata.ConvertEmptyStringToNull = true (that is default)

You will see both First and Last as null when the request doesn't contains values for these items.

With ModelMetadata.ConvertEmptyStringToNull = false

The properties will be "" when the request contains those parameters with empty values. If the request doesn't contain the parameter itself then still the value will be null.

VJAI
  • 32,167
  • 23
  • 102
  • 164