parse-community / Parse-SDK-dotNET

Parse SDK for .NET, Xamarin, Unity.
http://parseplatform.org
Apache License 2.0
323 stars 260 forks source link

ParseObject.get<float> uses device locale with Newtonsoft json : how to change it ? #305

Closed thibautvdu closed 5 years ago

thibautvdu commented 5 years ago

Hello everyone,

I'm using Parse in a Xamarin form application. Everything was working fine until I tried it on a smartphone with a French locale. Here is the issue:

public class ParseObjectHandler
{
    public readonly string Id;
    public ParseObject RemoteObject { get; private set; }
    public DateTime? CreatedAt { get => RemoteObject?.CreatedAt; }
    public DateTime? UpdatedAt { get => RemoteObject?.CreatedAt; }

    protected T GetValue<T>([CallerMemberName] string name = "")
    {
        string parseName = Char.ToLowerInvariant(name[0]) + name.Substring(1);
        T res = default(T);
        try
        {
            RemoteObject.TryGetValue<T>(parseName, out res);
        }
        catch(Exception e)
        {
            Debug.WriteLine("exception while getting value: " + e.Message);
        }

        return res;
    }
}

Calling the previous code with T = float fails only on my French phone because the floats in my mongo database are using the invariant culture ' 1.0 ' instead of the french ' 1,0 '. Here is the exception:

{System.FormatException: Input string was not in a correct format.
  at System.Number.ParseSingle (System.String value, System.Globalization.NumberStyles options, System.Globalization.NumberFormatInfo numfmt) [0x00083] in <fe08c003e91342eb83df1ca48302ddbb>:0 
  at System.Single.Parse (System.String s, System.Globalization.NumberStyles style, System.Globalization.NumberFormatInfo info) [0x00000] in <fe08c003e91342eb83df1ca48302ddbb>:0 
  at System.Single.Parse (System.String s, System.Globalization.NumberStyles style, System.IFormatProvider provider) [0x0000e] in <fe08c003e91342eb83df1ca48302ddbb>:0 
  at System.Convert.ToSingle (System.String value, System.IFormatProvider provider) [0x00009] in <fe08c003e91342eb83df1ca48302ddbb>:0 
  at System.String.System.IConvertible.ToSingle (System.IFormatProvider provider) [0x00000] in <fe08c003e91342eb83df1ca48302ddbb>:0 
  at System.Convert.ChangeType (System.Object value, System.Type conversionType, System.IFormatProvider provider) [0x0018e] in <fe08c003e91342eb83df1ca48302ddbb>:0 
  at System.Convert.ChangeType (System.Object value, System.Type conversionType) [0x0000c] in <fe08c003e91342eb83df1ca48302ddbb>:0 
  at Parse.Utilities.Conversion.ConvertTo[T] (System.Object value) [0x0001e] in <5d1c0c2b96a7483d85e5c63b3e156125>:0 
  at Parse.ParseObject.TryGetValue[T] (System.String key, T& result) [0x00021] in <5d1c0c2b96a7483d85e5c63b3e156125>:0 
  at AppInclood.Models.ParseObjectHandler.GetValue[T] (System.String name) [0x0002b] in C:\Users\thiba\Documents\Projets clients\Inclood\AppGrial\AppInclood\Models\ParseObjectHandler.cs:25 }

Is there anyway to tell Parse to stick up with the invariant culture when Parsing ? Also, I don't remind having issue before adding the Newtonsoft json nuget in my project. Did Parse just pick it up because it saw it was available ?

Any help would be appreciated. As a quick and dirty fix, I'm currently catching the exception, retrieving the value as a string and then parsing it manually.

Many thanks,

Thibaut

TobiasPott commented 5 years ago

Indeed does the Convert.ChangeType call inside the Parse.Utilities.Conversion.ConvertTo method does not handle invariant formatting of the number although the Json class does encode them with the invariant culture.

Depending on how eager you are to try to solve this issue without waiting for a commit to the repository you might take a look at line 57 and line 68 in the Conversion.cs file and add the invariant culture to the Convert.ChangeType calls inside the method to get it looking like return (T) Convert.ChangeType(value, typeof(T), System.Globalization.CultureInfo.InvariantCulture);

I'll prepare the changes but cannot tell when I have the commit ready to be pushed to the main repository as I don't want to rush it without adding tests to the project and check if it does not break anything else.

TobiasPott commented 5 years ago

@TheFanatr I have a fix for this issue prepared and added a test to the Parse.Test solution.

I'm a bit confused though as you mentioned that in Debug|Any CPU configuration the internals of the Parse assembly should be available to Parse.Test but I still need to add [assembly: System.Runtime.CompilerServices.InternalsVisibleTo("Parse.Test")] somewhere to the Parse assembly code base to get the Parse.Test to compile.

Did I miss anything to get access of the internals inside test methods?

TobiasPott commented 5 years ago

I've prepared a fix for this issue a while ago and finally got the time to put it up as a pull request. @thibautvdu Would you mind to check whether the commit mentioned above does fix this issue for you (I've tested it with german locale which should behave similar to a french one and want to have it validated before I merge it)