Solución:
Puede manejar ambos formatos (la representación del número JSON y el formato de cadena enmascarada) usando un JsonConverter
clase como esta.
class DecimalConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return (objectType == typeof(decimal) || objectType == typeof(decimal?));
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JToken token = JToken.Load(reader);
if (token.Type == JTokenType.Float || token.Type == JTokenType.Integer)
{
return token.ToObject<decimal>();
}
if (token.Type == JTokenType.String)
{
// customize this to suit your needs
return Decimal.Parse(token.ToString(),
System.Globalization.CultureInfo.GetCultureInfo("es-ES"));
}
if (token.Type == JTokenType.Null && objectType == typeof(decimal?))
{
return null;
}
throw new JsonSerializationException("Unexpected token type: " +
token.Type.ToString());
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
Para conectar esto a su carpeta, simplemente agregue una instancia del convertidor a la Converters
lista en el JsonSerializerSettings
objeto:
JsonSerializerSettings settings = new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore,
MissingMemberHandling = MissingMemberHandling.Ignore,
Formatting = Formatting.None,
DateFormatHandling = DateFormatHandling.IsoDateFormat,
Converters = new List<JsonConverter> { new DecimalConverter() }
};
¡Muchas gracias! Estaba buscando una solución para hacer que los decimales siempre se serializaran de manera similar y esta publicación me envió en la dirección correcta. Este es mi codigo:
internal class DecimalConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return (objectType == typeof(decimal) || objectType == typeof(decimal?));
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
Decimal? d = default(Decimal?);
if (value != null)
{
d = value as Decimal?;
if (d.HasValue) // If value was a decimal?, then this is possible
{
d = new Decimal?(new Decimal(Decimal.ToDouble(d.Value))); // The ToDouble-conversion removes all unnessecary precision
}
}
JToken.FromObject(d).WriteTo(writer);
}
}
Como una extensión de la respuesta de Kwaazaar, también agregué la forma inversa al convertidor (en su ejemplo arroja un NotImplementedException
.
namespace Something.Converter
{
using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
/// <inheritdoc cref="JsonConverter"/>
/// <summary>
/// Converts an object to and from JSON.
/// </summary>
/// <seealso cref="JsonConverter"/>
public class DecimalConverter : JsonConverter
{
/// <summary>
/// Gets a new instance of the <see cref="DecimalConverter"/>.
/// </summary>
public static readonly DecimalConverter Instance = new DecimalConverter();
/// <inheritdoc cref="JsonConverter"/>
/// <summary>
/// Determines whether this instance can convert the specified object type.
/// </summary>
/// <param name="objectType">Type of the object.</param>
/// <returns>
/// <c>true</c> if this instance can convert the specified object type; otherwise, <c>false</c>.
/// </returns>
/// <seealso cref="JsonConverter"/>
public override bool CanConvert(Type objectType)
{
return objectType == typeof(decimal) || objectType == typeof(decimal?);
}
/// <inheritdoc cref="JsonConverter"/>
/// <summary>
/// Reads the JSON representation of the object.
/// </summary>
/// <param name="reader">The <see cref="JsonReader"/> to read from.</param>
/// <param name="objectType">Type of the object.</param>
/// <param name="existingValue">The existing value of object being read.</param>
/// <param name="serializer">The calling serializer.</param>
/// <returns>The object value.</returns>
/// <seealso cref="JsonConverter"/>
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (!(reader.Value is string value))
{
if (objectType == typeof(decimal?))
{
return null;
}
return default(decimal);
}
// ReSharper disable once StyleCop.SA1126
if (decimal.TryParse(value, out var result))
{
// ReSharper disable once StyleCop.SA1126
return result;
}
if (objectType == typeof(decimal?))
{
return null;
}
return default(decimal);
}
/// <inheritdoc cref="JsonConverter"/>
/// <summary>
/// Writes the JSON representation of the object.
/// </summary>
/// <param name="writer">The <see cref="JsonWriter"/> to write to.</param>
/// <param name="value">The value.</param>
/// <param name="serializer">The calling serializer.</param>
/// <seealso cref="JsonConverter"/>
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var d = default(decimal?);
if (value != null)
{
d = value as decimal?;
if (d.HasValue)
{
d = new decimal(decimal.ToDouble(d.Value));
}
}
JToken.FromObject(d ?? 0).WriteTo(writer);
}
}
}
Para conectar esto en su carpeta, simplemente agregue una instancia del convertidor a la lista Converters en el objeto JsonSerializerSettings:
JsonSerializerSettings settings = new JsonSerializerSettings
{
// Some other settings.
Converters = new List<JsonConverter> { new DecimalConverter() }
};
o
JsonSerializerSettings settings = new JsonSerializerSettings
{
// Some other settings.
Converters = new List<JsonConverter> { DecimalConverter.Instance }
};