MVC 3 empty query string parameter value is bound as an empty string rather than null

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

Answers


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


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.


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.


Need Your Help

Netcat on remote machine using ssh

c++ c ssh netcat

I was trying to run netcat by using ssh and seems that my code always fails in my C code. Here are the commands which I am executing using system() in this order.

Pass ng-model as argument in directive angualjrs

javascript jquery angularjs angularjs-directive

I am writing a directive in AngularJs and I want to pass ng-model as an argument.