Kevin Cruijssen
Kevin Cruijssen

Reputation: 9336

ParseBigInteger FormatException in RavenDB source code

In our WPF app we have an input validation. One of the input values is a decimal and it allows a max of 28 digits (like 999999999999999999999999999). One more 9 and it gives a validation error feedback, but 28 9's work as intended.

However, when we try to save it to the RavenDB it gives an BigIntegerParse FormatException and I can't figure out why. I thought the size of a BigInteger is almost infinite (if I'm not mistaken it has a byte-max equal to Integer.MAX_VALUE, although I'm not sure). Still, you would assume a BigInteger Parse would have no trouble converting a string with 28 9's into a BigInteger.

Here is part of the StackTrace:

System.FormatException: The value could not be parsed.
   at System.Numerics.BigNumber.ParseBigInteger(String value, NumberStyles style, NumberFormatInfo info)
   at Raven.Imports.Newtonsoft.Json.JsonTextReader.ParseNumber() in c:\Builds\RavenDB-Stable-3.0\Imports\Newtonsoft.Json\Src\Newtonsoft.Json\JsonTextReader.cs:line 1288
   at Raven.Imports.Newtonsoft.Json.JsonTextReader.ParseValue() in c:\Builds\RavenDB-Stable-3.0\Imports\Newtonsoft.Json\Src\Newtonsoft.Json\JsonTextReader.cs:line 1010
   at Raven.Imports.Newtonsoft.Json.JsonTextReader.ReadInternal() in c:\Builds\RavenDB-Stable-3.0\Imports\Newtonsoft.Json\Src\Newtonsoft.Json\JsonTextReader.cs:line 383
   at Raven.Imports.Newtonsoft.Json.JsonTextReader.Read() in c:\Builds\RavenDB-Stable-3.0\Imports\Newtonsoft.Json\Src\Newtonsoft.Json\JsonTextReader.cs:line 304
   at Raven.Json.Linq.RavenJObject.Load(JsonReader reader) in c:\Builds\RavenDB-Stable-3.0\Raven.Abstractions\Json\Linq\RavenJObject.cs:line 251
   at Raven.Json.Linq.RavenJObject.Load(JsonReader reader) in c:\Builds\RavenDB-Stable-3.0\Raven.Abstractions\Json\Linq\RavenJObject.cs:line 211
   at Raven.Json.Linq.RavenJObject.Load(JsonReader reader) in c:\Builds\RavenDB-Stable-3.0\Raven.Abstractions\Json\Linq\RavenJObject.cs:line 211
   at Raven.Json.Linq.RavenJArray.Load(JsonReader reader) in c:\Builds\RavenDB-Stable-3.0\Raven.Abstractions\Json\Linq\RavenJArray.cs:line 139
   ...

I've looked up the source code of the first StackTrace line (c:\Builds\RavenDB-Stable-3.0\Imports\Newtonsoft.Json\Src\Newtonsoft.Json\JsonTextReader.cs:line 1288) and found it here: RavenDB JsonTextReader.

Line 1288 has the following code:

1284        else if (parseResult == ParseResult.Overflow)
1285        {
1286    #if !(NET20 || NET35 || SILVERLIGHT || PORTABLE40 || PORTABLE)
1287            string number = _stringReference.ToString();
{1288}          numberValue = BigInteger.Parse(number, CultureInfo.InvariantCulture);
1289            numberType = JsonToken.Integer;
1290    #else
1291            // todo - validate number was a valid integer to make sure overflow was the reason for failure
1292            throw JsonReaderException.Create(this, "JSON integer {0} is too large or small for an Int64.".FormatWith(CultureInfo.InvariantCulture, _stringReference.ToString()));
1293    #endif
1294        }

So, my question: What is the max value this Parser can hold in the RavenDB source code? If I knew the max I can adjust the validation class we use to set that as the max, instead of the default decimal's max. (We use RavenDB to save Event-states and our project uses a CQRS architecture.)

Upvotes: 0

Views: 176

Answers (1)

Dennis
Dennis

Reputation: 37780

Looks like the problem is in how RavenDb deserializes JSON. Here's a sample. Let's declare sample model:

public class Foo
{
    public decimal Bar { get; set; }
}

...and serialize it into JSON:

var serializer = new JsonSerializer();
var sb = new StringBuilder();
var foo = new Foo
{
    Bar = 9999999999999999999999999999M
};

using (var textWriter = new StringWriter(sb))
using (var jsonWriter = new JsonTextWriter(textWriter))
{
    serializer.Serialize(jsonWriter, foo);
}

Debug.WriteLine(sb);

Output will contain this:

{"Bar":9999999999999999999999999999.0}

Note, that there's a fractional part in a string representation. Of course, if you then try to parse this value as BigInteger (as RavenDb does), you'll get FormatException, because this string is invalid for BigInteger.

What you could do here? Honestly, I don't know... may be, it is better to store the data in your model as BigInteger, if it is a big integer?

Upvotes: 1

Related Questions