diff --git a/CryptoExchange.Net.UnitTests/SystemTextJsonConverterTests.cs b/CryptoExchange.Net.UnitTests/SystemTextJsonConverterTests.cs index ee8c3bb..a43a642 100644 --- a/CryptoExchange.Net.UnitTests/SystemTextJsonConverterTests.cs +++ b/CryptoExchange.Net.UnitTests/SystemTextJsonConverterTests.cs @@ -214,6 +214,41 @@ namespace CryptoExchange.Net.UnitTests var output = JsonSerializer.Deserialize($"{{ \"Value\": {val} }}"); Assert.That(output.Value == expected); } + + [TestCase("1", 1)] + [TestCase("1.1", 1.1)] + [TestCase("-1.1", -1.1)] + [TestCase(null, null)] + [TestCase("", null)] + [TestCase("null", null)] + [TestCase("1E+2", 100)] + [TestCase("1E-2", 0.01)] + [TestCase("80228162514264337593543950335", -999)] // -999 is workaround for not being able to specify decimal.MaxValue + public void TestDecimalConverterString(string value, decimal? expected) + { + var result = JsonSerializer.Deserialize("{ \"test\": \""+ value + "\"}"); + Assert.That(result.Test, Is.EqualTo(expected == -999 ? decimal.MaxValue : expected)); + } + + [TestCase("1", 1)] + [TestCase("1.1", 1.1)] + [TestCase("-1.1", -1.1)] + [TestCase("null", null)] + [TestCase("1E+2", 100)] + [TestCase("1E-2", 0.01)] + [TestCase("80228162514264337593543950335", -999)] // -999 is workaround for not being able to specify decimal.MaxValue + public void TestDecimalConverterNumber(string? value, decimal? expected) + { + var result = JsonSerializer.Deserialize("{ \"test\": " + value + "}"); + Assert.That(result.Test, Is.EqualTo(expected == -999 ? decimal.MaxValue : expected)); + } + } + + public class STJDecimalObject + { + [JsonConverter(typeof(DecimalConverter))] + [JsonPropertyName("test")] + public decimal? Test { get; set; } } public class STJTimeObject diff --git a/CryptoExchange.Net/Converters/JsonNet/BigDecimalConverter.cs b/CryptoExchange.Net/Converters/JsonNet/BigDecimalConverter.cs new file mode 100644 index 0000000..ad773b1 --- /dev/null +++ b/CryptoExchange.Net/Converters/JsonNet/BigDecimalConverter.cs @@ -0,0 +1,62 @@ +using System; +using System.Globalization; +using Newtonsoft.Json; + +namespace CryptoExchange.Net.Converters.JsonNet +{ + /// + /// Decimal converter that handles overflowing decimal values (by setting it to decimal.MaxValue) + /// + public class BigDecimalConverter : JsonConverter + { + /// + public override bool CanConvert(Type objectType) + { + if (Nullable.GetUnderlyingType(objectType) != null) + return Nullable.GetUnderlyingType(objectType) == typeof(decimal); + return objectType == typeof(decimal); + } + + /// + public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) + { + if (reader.TokenType == JsonToken.Null) + return null; + + if (reader.TokenType == JsonToken.Float || reader.TokenType == JsonToken.Integer) + { + try + { + return decimal.Parse(reader.Value!.ToString(), NumberStyles.Float, CultureInfo.InvariantCulture); + } + catch (OverflowException) + { + // Value doesn't fit decimal; set it to max value + return decimal.MaxValue; + } + } + + if (reader.TokenType == JsonToken.String) + { + try + { + var value = reader.Value!.ToString(); + return decimal.Parse(value, NumberStyles.Float, CultureInfo.InvariantCulture); + } + catch (OverflowException) + { + // Value doesn't fit decimal; set it to max value + return decimal.MaxValue; + } + } + + return null; + } + + /// + public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) + { + writer.WriteValue(value); + } + } +} \ No newline at end of file diff --git a/CryptoExchange.Net/Converters/SystemTextJson/BigDecimalConverter.cs b/CryptoExchange.Net/Converters/SystemTextJson/BigDecimalConverter.cs new file mode 100644 index 0000000..0a24dc1 --- /dev/null +++ b/CryptoExchange.Net/Converters/SystemTextJson/BigDecimalConverter.cs @@ -0,0 +1,46 @@ +using System; +using System.Globalization; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace CryptoExchange.Net.Converters.SystemTextJson +{ + /// + /// Decimal converter that handles overflowing decimal values (by setting it to decimal.MaxValue) + /// + public class BigDecimalConverter : JsonConverter + { + /// + public override decimal Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType == JsonTokenType.String) + { + try + { + return decimal.Parse(reader.GetString(), NumberStyles.Float, CultureInfo.InvariantCulture); + } + catch(OverflowException) + { + // Value doesn't fit decimal, default to max value + return decimal.MaxValue; + } + } + + try + { + return reader.GetDecimal(); + } + catch(FormatException) + { + // Format issue, assume value is too large + return decimal.MaxValue; + } + } + + /// + public override void Write(Utf8JsonWriter writer, decimal value, JsonSerializerOptions options) + { + writer.WriteNumberValue(value); + } + } +} diff --git a/CryptoExchange.Net/Converters/SystemTextJson/DecimalConverter.cs b/CryptoExchange.Net/Converters/SystemTextJson/DecimalConverter.cs index ae9f36d..ed0a4cf 100644 --- a/CryptoExchange.Net/Converters/SystemTextJson/DecimalConverter.cs +++ b/CryptoExchange.Net/Converters/SystemTextJson/DecimalConverter.cs @@ -22,10 +22,26 @@ namespace CryptoExchange.Net.Converters.SystemTextJson if (string.IsNullOrEmpty(value) || string.Equals("null", value)) return null; - return decimal.Parse(value, NumberStyles.Float, CultureInfo.InvariantCulture); + try + { + return decimal.Parse(value, NumberStyles.Float, CultureInfo.InvariantCulture); + } + catch(OverflowException) + { + // Value doesn't fit decimal, default to max value + return decimal.MaxValue; + } } - return reader.GetDecimal(); + try + { + return reader.GetDecimal(); + } + catch(FormatException) + { + // Format issue, assume value is too large + return decimal.MaxValue; + } } ///