Model binder can't handle double.MAX string re

2019-08-03 23:59发布

问题:

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.

回答1:

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.