asp.net-mvcstringtype-conversiondoublemodelbinder

Model binder can't handle double.MAX string representation back to double


Right now I have a ViewModel with a property double Maximum. On the view side it's kept in a hidden input to help with unobtrusive validation.

When post backing the values, the binding silently fails. I had to put a breakpoint on this line:

if(ModelState.IsValid)

and check which ModelState property had an error. Then I found that this double Maximum property had an error with the following message:

The parameter conversion from type 'System.String' to type 'System.Double' failed. See the inner exception for more information.

On the view side inspecting the HTML with Firebug I can see that the hidden input has this value:

1.79769313486232E+308

which correctly represents double.MAX constant.

I found this Scott Hanselman post from Jan/2005 (almost 9 years ago) which deals with something similar:

Why you can't Double.Parse(Double.MaxValue.ToString()) or System.OverloadExceptions when using Double.Parse

Is there something wrong with my app config or this direct conversion from string back to double is not supported? I think it should handle it without errors.

Note: I tried changing the hidden input value with Firebug and did as Scott mentions on his post: I subtracted 1 from the last digit...

1.79769313486231E+308

and did a postback again just to find the model binder handled it correctly this time.


Solution

  • I'm using @Html.HiddenFor to create the hidden input.

    After carefully reading Scott's post I saw that he mentions the round-trip specifier. I also found an example here on StackOverflow.

    The R stands for "round-trip". From MSDN:

    This format is supported only for the Single and Double types. The round-trip specifier guarantees that a numeric value converted to a string will be parsed back into the same numeric value.

    So I did this:

    @Html.HiddenFor(m => m.Maximum,
                    new { Value = Model.Maximum.ToString("R") })
    

    Now this gives me a double.MAX string representation that can be round-tripped back to a double on the controller side:

    1.7976931348623157E+308
    

    Nice... problem solved.

    Hope it helps anyone that might face this same problem in the future.


    How interesting this is?!

    1.79769313486232E+308   // double.MAX
    1.7976931348623157E+308 // double.MAX.ToString("R")
    

    It's worth mentioning that all this is also applicable to double.MIN.