Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Model Binding - Nullable decimal and double default to 0 instead of null?

When my form posts to my controller action, and the form is bound to my model, blank form values for nullable doubles and decimals default to 0, but blank form values for nullable ints default to null. Is this right?

My model has nullable types for several fields that can be blank. It has nullable ints, doubles, and decimals. I then have a regular form that has textboxes for each of these properties, and they all default to blank (empty string). When this form is posted back to my controller action with all empty form values, and it's bound to my model, the empty doubles and decimals show up as 0, and the empty ints are null.

It seems to me all nullable types should default to null when an empty form value is passed in, but even if that's not the case, it seems very inconsistent that doubles and decimals are treated different than ints.

like image 363
wired_in Avatar asked Jan 20 '13 05:01

wired_in


1 Answers

This issue appears to be resolved in MVC4, as I could not reproduce the problem. My empty textboxes all bind back null to my model's nullable int, double, or decimal. No issues. So the issue may be somewhere else, or it's possible this used to be a bug in MVC3 and isn't any longer.

That said, if you're still encountering the problem and can't use MVC4, try making your own custom model binders to do exactly what you need to do. Here's an example one for decimal:

public class NullableDecimalBinder : IModelBinder {

    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) {
        ValueProviderResult valueResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
        ModelState modelState = new ModelState { Value = valueResult };
        object result = null;

        if (valueResult.AttemptedValue.Length > 0) {
            try {
                // Bonus points: This will bind using the user's current culture.
                result = Convert.ToDecimal(valueResult.AttemptedValue, System.Globalization.CultureInfo.CurrentCulture);
            } catch (FormatException e) {
                modelState.Errors.Add(e);
            } catch (InvalidOperationException e) {
                modelState.Errors.Add(e);
            }
        }

        bindingContext.ModelState.Add(bindingContext.ModelName, modelState);
        return result;
    }
}

Then, to use it, add this line to your Global.asax's Application_Start:

ModelBinders.Binders.Add(typeof(decimal?), new NullableDecimalBinder());
like image 126
Ber'Zophus Avatar answered Oct 22 '22 19:10

Ber'Zophus