0

I have a problem that I checked some time ago and also posted on Microsoft Github since it seemed a bug, I'm speaking of years ago. I was checking if was solved but it seems no.

It is a trivial thing: I'm using Google Maps APIs with an autocomplete to retrieve an address, collecting the information along with latitude and longitude and pass it via jQuery POST to an MVC Controller (.net 6) to store it. All the values are deserialized fine, the latitude and longitude are interpreted in a wrong way, they lose the floating point. This happens when I use a combination of cultures which is different from en-US in the browser but it can happen also in other circumstances.

The code I use to send it, is briefly this:

var propertyToSave = { IDUser: 0 };

// GOOGLE AUTOCOMPLETE SELECTED PLACE IN VAR selectedPlace
console.log(selectedPlace.geometry.location.lat());
console.log(selectedPlace.geometry.location.lng());
propertyToSave.Latitude = selectedPlace.geometry.location.lat();
propertyToSave.Longitude = selectedPlace.geometry.location.lng();
// other properties...

$.ajax({
    url: 'url',
    data: { property: propertyToSave, __RequestVerificationToken: $('input[name=__RequestVerificationToken]').first().val() },
    timeout: DEFAULT_AJAX_TIMEOUT,
    dataType: 'json',
    method: 'POST'
}).done(function (data, textStatus, jqXHR) {
    // MANAGING RESPONSE
}).fail(function (jqXHR, textStatus, errorThrown) {
    // MANAGING RESPONSE
});

At this point when I make the Ajax call everything streams fine until the controller deserializes the value, this is what I see in the browser console. Everything matches until the controller is deserializing the value and losing the floating point.

The json sent (converting latitude and longitude in the client as string with JSON.stringify to avoid any culture interference) looks like:

{
  "IDProperty": 0,
  "IDUser": 0,
...
  "Latitude": "-34.8272987",
  "Longitude": "-56.1201179",
...
}

The signature of the controller accepts an object that reflect exactly the json sent

[Authorize]
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<JsonResult> ExecuteSubmit(PropertyViewModel property)

Console Log:

enter image description here

Console XHR Call:

enter image description here

What the controller deserializes:

enter image description here

I mean it's weird that after many time the problems is not solved yet, I also tried to pass the value untouched as a string serializing it before sending it in this way but it didn't help

JSON.stringify(selectedPlace.geometry.location.lng())

Abyway faced this problem and solved it? The only way to solve I have found is to create other two string properties and sending it as string then deserializing it manually but it's a workaround

Many thanks

ollie10
  • 317
  • 2
  • 11
  • You are serializing using the client culture. I think you need to send the lat and long in the culture (languaje) of the SO running the controller (because he the one who needs to deserialize) or send the culture with the data and use it to deserialize in controller – J.Salas Apr 22 '22 at 10:56
  • This is not a solution because there can be many combinations: culture of the develompment machine, culture of the production server culture of the clients (it's a public website and any client can have a different culture)... Furthermore js treat all the floating point using a point as US american, the machine I'm developing has US .net framework and still not deserializing it correctly since the browser is in Italian – ollie10 Apr 22 '22 at 10:59
  • You are sending the data from _front_ to somewhere that MUST understand it _(back)_ just make sure the _back_ can deserialize with the correct culture. Also what is the signature of the back Action? – J.Salas Apr 22 '22 at 11:03
  • If I'm sending a value in the proper US format 1.234 and not 1,234 I'm expecting that a machine running Windows in US english, with Visual Studio in US english, with .net framework in US english would deserialize the value correctly no matter which is the culture of the browser sending it. How half of the world websites would work so? They interpret the culture of the numbers that javascript set 40 years ago using the floating point not comma? The back action takes an Object with the properties as a normal MVC controller would do – ollie10 Apr 22 '22 at 11:07
  • Why don't you use strings instead of doubles? – anastaciu Apr 22 '22 at 11:11
  • That's what I'm doing right now but it's a workaround, it's ridicolous the framework cannot deserialize a number sent by in the propert format – ollie10 Apr 22 '22 at 11:13
  • I had some issues in the past with ajax too, in my case with decimal, I remember vaguely I fixed the issue by getting the current culture in the frontend and using it to send the correct values, and by that I mean values that where correctly parsed in the controller, I don't quite remember what I did, sadly. I only use decimal/double if I absolutely have to, it's a can of worms. – anastaciu Apr 22 '22 at 11:20
  • If I remember correctly it involved converting the value using `.toLocaleString(culture)`, passing the current culture as parameter, after that it would deserialize properly. But you're right, this should be handled correctly by the framework, it's not a recent problem either... – anastaciu Apr 22 '22 at 11:37
  • 1
    They don't seem to be interested in resolving this as ajax is not viewed as a propper way of view/controller comunication by them. And by propper I mean one that they like to see be used. If you use the *normal* aspnet method *i.e.* via `form` it works good in most cases. – anastaciu Apr 22 '22 at 11:46
  • 1
    Might you please [edit] your question to include your JSON as **text** rather than as a screenshot? On stack overflow images should not be used for textual content, see [*Discourage screenshots of code and/or errors*](https://meta.stackoverflow.com/a/307500) and [*Why not upload images of code on SO when asking a question*](https://meta.stackoverflow.com/a/285557) for why. A [mcve] showing your JSON ans server code would be ideal, and maximize your chance of getting help. – dbc Apr 22 '22 at 13:12
  • But if your problem is that you are using a comma as a decimal separator in your JSON, then your JSON is malformed. JSON is a culture-invariant text-based language-independent data interchange format, which, according to the [JSON Standard](https://www.rfc-editor.org/rfc/rfc8259#section-6), uses a decimal point not a comma: *`decimal-point = %x2E ; .`*. Since that's the standard, that's what System.Text.Json supports. – dbc Apr 22 '22 at 13:19
  • hello @dbc probably you didn't read the question, the comma isn't involved nowhere, I'm using the standard point notation everywhere as you see in the image. So far the only solution was offered by MS using a custom deserializer for doing something that the framework should do out of the box... https://github.com/dotnet/runtime/issues/1366#issuecomment-1106489952 – ollie10 Apr 22 '22 at 15:09
  • @ollie10 - I read the title, which explicitly mentions culture: *unable to deserialize doubles properly with culture*. Might you please [edit] your question to include the raw JSON (or request) you are trying to deserialize? When I run your code snippet all I see is an error. See [ask]. – dbc Apr 22 '22 at 15:13
  • @ollie10 - I can't reproduce your problem in a simple unit test. If I change the current culture and UI cultures to `new CultureInfo("es-ES")`, `JsonSerializer.Deserialize("-34.8272987")` correctly returns `-34.8272987M`. See https://dotnetfiddle.net/dYJ7Iw. – dbc Apr 22 '22 at 15:27
  • I added more details anyway from MS they provided a more or less elegant workaround https://github.com/dotnet/runtime/issues/1366#issuecomment-1106621447 – ollie10 Apr 22 '22 at 15:43
  • Hmm, still can't reproduce in a unit test. Your decimal values are strings, like so: `"-34.8272987"`. System.Text.Json won't deserialize string values to decimal by default, if I try it throws an error: *`System.Text.Json.JsonException: The JSON value could not be converted to System.Decimal`*. See https://dotnetfiddle.net/K7JwgW. But if I set `JsonSerializerOptions.NumberHandling = JsonNumberHandling.AllowReadingFromString` then everything seems to work correctly, see https://dotnetfiddle.net/fuqwi7. – dbc Apr 22 '22 at 16:03
  • The problem cannot be reproduced as easy as a test, the problem is that behind the box the controller makes some magic which uses the culture and expects a value with a comma since the browser says so and it shouldn't do it. On the original issue there where more information https://github.com/dotnet/runtime/issues/1366 – ollie10 Apr 22 '22 at 16:06
  • 1
    In that case the problem isn't with System.Text.Json, it's somewhere elsewhere in the stack. There's no way that System.Text.Json is trying to parse decimals using the current culture's decimal separator. That being said, your issue was opened against .Net Core 3.1 and System.Text.Json was pretty buggy back then. What if you switch to .NET 5 or 6 and send `Latitude` and `Longitude` as JSON numbers instead of strings? – dbc Apr 22 '22 at 16:15
  • I opened it on 3.1, currently I´m on 6 as described in the first message, still the same problem, Microsoft is aware of it but the didn´t prioritize it as they said. If I don´t send it as string i have the same problem plus some weird roinding point problems gave by javascript if the latitude or longitude has more decimals than the one expected by the controller (it can happen) https://www.matthewburfield.com/javascript-deep-dive-floating-point-numbers/ – ollie10 Apr 22 '22 at 17:24

0 Answers0