处理Newtonsoft.Json中的十进制值

我有一个MVC应用程序,我在其中处理一些JSON。 这很简单。 我在ModelBinder中有这么简单的代码:

return JsonConvert.DeserializeObject(jsonString, bindingContext.ModelType, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore, MissingMemberHandling = MissingMemberHandling.Ignore, Formatting = Formatting.None, DateFormatHandling = DateFormatHandling.IsoDateFormat, FloatParseHandling = FloatParseHandling.Decimal }); 

它完美无瑕。

好吧,有点。

假设我有这个课程:

 public class MyClass { public decimal MyProp { get; set; } } 

如果我尝试反序列化这个json:

 "{\"MyProp\": 9888.77}" 

当然它可以工作,因为9888.77是一个Javascript浮点值。 我认为。

但是我的页面中有一个屏蔽输入,使得JSON看起来像这样(对不起我的英文):

 "{\"MyProp\": \"9.888,77\" }" 

AAAND,它失败了。 它说它Could not convert string to decimal

好的,这很公平。 它不是JS浮点数,但Convert.ToDecimal("9.888,77")以我想要的方式工作。

我在互联网上阅读了一些关于自定义反序列化器的教程,但是我可以为我的应用程序中的每个类定义一个自定义反序列化器。

我想要的是简单地重新定义JSON.Net将字符串转换为十进制属性的方式,在任何我想要反序列化的类中。 我想在转换小数的过程中注入Convert.ToDecimal函数,当前转换器不起作用。

有没有办法可以做到?

我认为有办法做到这一点,所以我改变了我的代码。

 JsonSerializer serializer = new JsonSerializer { NullValueHandling = NullValueHandling.Ignore, MissingMemberHandling = MissingMemberHandling.Ignore, Formatting = Formatting.None, DateFormatHandling = DateFormatHandling.IsoDateFormat, FloatParseHandling = FloatParseHandling.Decimal, }; return serializer.Deserialize(new DecimalReader(jsonStr), bindingContext.ModelType); 

并创建了这个类:

 public class DecimalReader : JsonTextReader { public DecimalReader(string s) : base(new StringReader(s)) { } public override decimal? ReadAsDecimal() { try { return base.ReadAsDecimal(); } catch (Exception) { if (this.TokenType == JsonToken.String) { decimal value = 0; bool convertible = Decimal.TryParse(this.Value.ToString(), out value); if (convertible) { return new Nullable(value); } else { throw; } } else { throw; } } } } 

但它非常难看:它只在崩溃时执行我想要的东西, 并依赖于base.ReadAsDecimal()崩溃 。 它不可能更难看。

并且不起作用Error converting value "1.231,23" to type 'System.Nullable1[System.Decimal]'. Path 'MyProp', line X, position Y. Error converting value "1.231,23" to type 'System.Nullable1[System.Decimal]'. Path 'MyProp', line X, position Y.

值本身正在转换,但也许由于某种原因,它仍然试图将字符串“1.231,23”放入小数。

那么,有没有办法正确地做到这一点?

您可以使用像这样的自定义JsonConverter类来处理这两种格式(JSON数字表示和屏蔽字符串格式)。

 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(); } 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(); } } 

要将其插入到活页夹中,只需将转换器的实例添加到JsonSerializerSettings对象的Converters列表中:

 JsonSerializerSettings settings = new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore, MissingMemberHandling = MissingMemberHandling.Ignore, Formatting = Formatting.None, DateFormatHandling = DateFormatHandling.IsoDateFormat, Converters = new List { new DecimalConverter() } }; 

非常感谢! 我正在寻找一个解决方案,使得小数总是以类似的方式序列化,这篇文章发送给我正确的方向。 这是我的代码:

  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); } }