I have a JSON file with an array of objects, each containing a string value, grade
, that I'd like to parse to decimal.
The string value contains a valid decimal about 99% percent of the time, but in that 1%, I'm getting values such as "grade":"<1"
which is obviously not a valid decimal. The grade
property is about 1 of 100 properties that can sometimes be set to "<1"
.
This of course throws the following error:
Newtonsoft.Json.JsonReaderException: 'Could not convert string to decimal'
Here is how I am currently deserializing my JSON:
public static Product FromJson(string json) => JsonConvert.DeserializeObject<Product>(json, Converter.Settings);
Is there anything I can do to handle cases where I'm getting those pesky "<1"
values? Hopefully something that does the following: if attempting to deserialize a value to decimal, and if the value cannot be parsed to decimal, default to zero.
Any ideas if this is possible? I obviously don't want to have to update my table columns to switch all values from decimal to varchar, because that just sucks and is going to require decimal <-> varchar conversions every time someone wants to query my data.
You can solve this problem by making a custom JsonConverter
to handle the decimals:
class TolerantDecimalConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(decimal);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Float || reader.TokenType == JsonToken.Integer)
{
return Convert.ToDecimal(reader.Value);
}
if (reader.TokenType == JsonToken.String && decimal.TryParse((string)reader.Value, out decimal d))
{
return d;
}
return 0.0m;
}
public override bool CanWrite
{
get { return false; }
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
To use the converter, just add an instance to the Converters
collection in the JsonSerializerSettings
that you are passing to JsonConvert.DeserializeObject<T>
.
Settings.Converters.Add(new TolerantDecimalConverter());
Note: since you are using decimals, you should probably also set FloatParseHandling
to Decimal
if you are not already; the default is Double
.
Settings.FloatParseHandling = FloatParseHandling.Decimal;
Working demo here: https://dotnetfiddle.net/I4n00o