处理Newtonsoft.Json中的十进制值 [英] Handling decimal values in Newtonsoft.Json

查看:512
本文介绍了处理Newtonsoft.Json中的十进制值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

编辑:已经差不多5年了,我认为这不是一条路。客户端应以正确的数字格式发布数据。使用当前的框架,如React或Angular,或具有适当的架构和错误处理&验证,我认为这几乎不是问题。

It's been almost 5 years and I don't think this is the way to go. The client should post the data in the correct numerical format. With current frameworks like React or Angular, or with a proper architecture and error handling & validation, i think this is almost a non-problem.

但是如果有人想要展示他们的Json.NET肌肉,请随时查看答案。

But if anyone wishes to flex their Json.NET muscles, feel free to check the answers.

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

I have a MVC application and I handle some JSON in it. That's simple. I have this simple piece of code in my 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:

If I try to deserialize this json:

"{\"MyProp\": 9888.77}"

当然可行,因为 9888.77 是一个Javascript浮点值。我想。

Of course it works, since 9888.77 is a Javascript float value. I think.

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

But I have a masked input for money in my page that makes the JSON look like this (sorry about my english):

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

AAAND,它失败了。它说它无法将字符串转换为十进制

AAAND, it fails. It says that it Could not convert string to decimal.

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

Ok, that's fair. It is not a JS float, but Convert.ToDecimal("9.888,77") works the way I want.

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

I've read some tutorials on the internet about custom deserializers, but its inviable for me to define a custom deserializer for every single class I have in my application.

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

What I want is to simple redefine the way JSON.Net converts a string to a decimal property, in any class i'll ever want to deserialize to. I want to inject the Convert.ToDecimal function in the process of converting decimals, when the current converter doesn't work.

有没有办法可以做到?

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

I thought there was a way to do it, so I changed my code a little bit.

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<decimal>(value);
                }
                else { throw; }
            }
            else
            {
                throw;
            }
        }
    }
}

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

But it is very ugly: it executes what I want only when it crashes, and depends on base.ReadAsDecimal() crashing. It couldn't be more ugly.

并且不起作用将值1.231,23转换为类型'System.Nullable1 [系统时出错.Decimal]。路径'MyProp',第X行,第Y位。

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

The value itself is being converted, but perhaps for some reason it still tries to put the string "1.231,23" into a decimal.

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

So, is there a way to do it properly?

推荐答案

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

You can handle both formats (the JSON number representation and the masked string format) using a custom JsonConverter class like this.

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

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

To plug this into your binder, just add an instance of the converter to the Converters list in the JsonSerializerSettings object:

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

这篇关于处理Newtonsoft.Json中的十进制值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆