I have a class ChargesDetail and am trying to deserialize json as shown below. Here I have used datatype that is Amount.
public class ChargesDetail
{
public double DiscountRate { get; set; }
public Amount DiscountAmount { get; set; }
}
public class Amount:IConvertible
{
private double _val = 0;
private int _decimal = 5;
public Amount()
{
}
public Amount(double amount): this()
{
// this.Value = amount;
_val = Math.Round(amount, _decimal);
}
#region IConvertible Members
// Implementation snipped
#endregion
}
And my JSON looks like:
{ "DiscountRate":0.0, "DiscountAmount":0.0 }
Am trying to deserialize as like this:
T result = JsonConvert.DeserializeObject<ChargesDetail>(json);
It is giving me an exception like:
Invalid cast from 'System.Double' to 'Amount'.
at System.Convert.DefaultToType(IConvertible value, Type targetType, IFormatProvider provider) at System.Double.System.IConvertible.ToType(Type type, IFormatProvider provider) at System.Convert.ChangeType(Object value, Type conversionType, IFormatProvider provider) at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.EnsureType(JsonReader reader, Object value, CultureInfo culture, JsonContract contract, Type targetType)
How to deserialize json to this customized datatype?
As your question indicates you are using json.net, you can serialize your Amount as a single decimal value using a custom JsonConverter:
public class AmountConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(Amount);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
// Would decimal be more appropriate than double?
var value = serializer.Deserialize<double?>(reader);
if (value == null)
return null;
return new Amount(value.Value);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
writer.WriteValue(((Amount)value).Value);
}
}
You can then either apply it to your model as follows:
[JsonConverter(typeof(AmountConverter))]
public class Amount : IConvertible
{
private double _val = 0;
private int _decimal = 5;
public double Value { get { return _val; } }
public Amount()
{
}
public Amount(double amount)
: this()
{
// this.Value = amount;
_val = Math.Round(amount, _decimal);
}
#region IConvertible Members
#endregion
}
Or add it in JsonSerializerSettings.Converters when serializing and deserializing:
var settings = new JsonSerializerSettings
{
Converters = { new AmountConverter() },
};
var = JsonConvert.DeserializeObject<T>(json, settings);
Notes:
If Amount is intended to represent a monetary quantity you might consider switching to decimal from double.
But if you do, you will need to switch to FloatParseHandling.Decimal at some higher level to prevent loss of precision during parsing by JsonTextReader. This can be done e.g. by setting JsonSerializerSettings.FloatParseHandling globally or by grabbing FloatParseHandlingConverter from this answer to Force decimal type in class definition during serialization and applying it to the parent class ChargesDetail like so:
[JsonConverter(typeof(FloatParseHandlingConverter), FloatParseHandling.Decimal)]
public class ChargesDetail
{
public decimal DiscountRate { get; set; }
public Amount DiscountAmount { get; set; }
}
Demo fiddle here.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With