避免将JSON字符串标记反序列化为数字属性

时间:2016-03-08 13:27:38

标签: c# json string json.net deserialization

JSON看起来像这样:

{
    "x": "50"
}

班级看起来像这样:

public class Test
{
    public float? x { get; set; }
}

使用时

var test = JsonConvert.DeserializeObject<Test>(json);

没有抛出异常,JSON.NET只转换字符串值&#34; 50&#34;浮动值为50.0。

这个问题是在输入验证的背景下提出的。我想得到一个例外,因为JSON字符串不符合合同(x字段应该是一个真正的浮点数。)

而且我不想在“测试”中使用属性注释。类。

是否有可以用来避免这种情况的JsonSerializerSettings?

1 个答案:

答案 0 :(得分:5)

JSON.NET自由地将数字字符串("50")解析为数字。据我所知,没有任何简单的方法可以解决这个问题。

你可以创建一个不允许这样做的自定义转换器:

public class NumberConverter : JsonConverter
{
    private readonly Type[] _typesNotToReadAsString = { typeof(float), typeof(float?) };

    public override bool CanConvert(Type objectType)
    {
        return _typesNotToReadAsString.Any(t => t.IsAssignableFrom(objectType));
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JToken token = JToken.Load(reader);

        if (_typesNotToReadAsString.Contains(objectType) && token.Type == JTokenType.String)
        {
            string exceptionString = string.Format("Won't convert string to type {0}", objectType.FullName);
            throw new JsonSerializationException(exceptionString);
        }

        return token.ToObject(objectType);
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }

    public override bool CanWrite
    {
        get { return false; }
    }
}

转换器报告能够反序列化为指定的类型,在本例中为floatfloat?,但可配置。

反序列化后,它会检查令牌类型。给定JSON输入的一些标记类型:

  • "50"JTokenType.String
  • 50JTokenType.Integer
  • 42.1415JTokenType.Float

这样,转换器可以确定当前令牌是否按照需要进行格式化。当令牌类型是一个字符串时,上面的转换器将抛出一个异常,表明它不会将字符串转换为所需的类型。

当令牌类型为其他任何内容时,转换器会通过token.ToObject(objectType)将令牌转换为适当的数字类型。该方法还将通过抛出相应的异常来处理非数字输入,例如“无法将数组转换为单个。”

鉴于课程Foo

public class Foo
{
    public float Bar { get; set; }
    public string Baz { get; set; }
    public float? Qux { get; set; }
}

使用上面的转换器反序列化JSON字符串,这将起作用:

var jsonString = "{ \"Bar\" : 50, \"Baz\" : \"zaB\", \"Qux\" : 42.1415 }";
var foo = JsonConvert.DeserializeObject<Foo>(jsonString, new NumberConverter());

虽然这会抛出:

var jsonString = "{ \"Bar\" : 50, \"Baz\" : \"zaB\", \"Qux\" : \"42.1415\" }";
var foo2 = JsonConvert.DeserializeObject<Foo>(jsonString, new NumberConverter());