JSON.NET liberally parses numbers-in-strings ("50") as numbers. There's no trivial way to turn this off, as far as I can find.
You could create a custom converter that disallows this:
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; }
}
}
The converter reports to be able to deserialize into specified types, in this case float and float?, but configurable.
Upon deserialization, it inspects the token type. Some token types for given JSON input:
"50": JTokenType.String
50: JTokenType.Integer
42.1415: JTokenType.Float
This way the converter can determine whether the current token is formatted as desired. When the token type is a string, the above converter will throw an exception stating it won't convert a string to the desired type.
When the token type is anything else, the converter will convert the token to the appropriate numeric type through token.ToObject(objectType). That method will also handle non-numeric input by throwing the appropriate exception, for example "Can not convert Array to Single.".
Given a class Foo:
public class Foo
{
public float Bar { get; set; }
public string Baz { get; set; }
public float? Qux { get; set; }
}
Deserialize a JSON string using above converter, this will work:
var jsonString = "{ \"Bar\" : 50, \"Baz\" : \"zaB\", \"Qux\" : 42.1415 }";
var foo = JsonConvert.DeserializeObject<Foo>(jsonString, new NumberConverter());
While this will throw:
var jsonString = "{ \"Bar\" : 50, \"Baz\" : \"zaB\", \"Qux\" : \"42.1415\" }";
var foo2 = JsonConvert.DeserializeObject<Foo>(jsonString, new NumberConverter());
[JsonIgnore]attribute