编辑:已经快 5 年了,我不认为这是要走的路。客户应以正确的数字格式发布数据。使用 React 或 Angular 等当前框架,或者具有适当的架构和错误处理和验证,我认为这几乎不是问题。
但如果有人希望展示他们的 Json.NET 肌肉,请随时查看答案。
我有一个 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<decimal>(value);
                }
                else { throw; }
            }
            else
            {
                throw;
            }
        }
    }
}
但它非常难看:它只在崩溃时执行我想要的,并且依赖base.ReadAsDecimal()crashing。不能更丑了。
并且不起作用:Error converting value "1.231,23" to type 'System.Nullable1[System.Decimal]'. Path 'MyProp', line X, position Y.
值本身正在被转换,但也许出于某种原因,它仍然尝试将字符串“1.231,23”转换为十进制。
那么,有没有办法正确地做到这一点?