问题描述
当我通过显式地使用Newtonsoft或通过ASP.NET Web Api的模型绑定机制将JSON反序列化为下面的C#对象时,字符串id
值将自动转换为int.我希望它会由于类型不匹配而引发异常或引发错误.这是JSON在规范中的工作方式吗?如果没有,如何防止这种自动转换?
When I deseiralize the JSON to the C# object below, either using Newtonsoft explicitly or via the model binding mechanism of ASP.NET Web Api, the string id
value is automatically converted to int. I would expect it to throw an exception or raise an error as there is a type mismatch. Is this how JSON is supposed to work in the specs? If not, how can I prevent such an automatic conversion?
JSON:{"id":"4", "name":"a"}
C#模型:int id; string name
JSON: {"id":"4", "name":"a"}
C# model: int id; string name
推荐答案
这是Json.NET的功能:在反序列化原始类型时,它将尽可能将原始JSON值转换为目标c#类型.由于字符串"4"
可以转换为整数,因此反序列化成功.如果您不希望使用此功能,则可以创建自定义JsonConverter
用于检查所读取的令牌是否确实是数字的整数类型(或null
,用于可为空的值):
This is a feature of Json.NET: when deserializing a primitive type, it will convert the primitive JSON value to the target c# type whenever possible. Since the string "4"
can be converted to an integer, deserialization succeeds. If you don't want this feature, you can create a custom JsonConverter
for integral types that checks that the token being read is really numeric (or null
, for a nullable value):
public class StrictIntConverter : JsonConverter
{
readonly JsonSerializer defaultSerializer = new JsonSerializer();
public override bool CanConvert(Type objectType)
{
return objectType.IsIntegerType();
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
switch (reader.TokenType)
{
case JsonToken.Integer:
case JsonToken.Float: // Accepts numbers like 4.00
case JsonToken.Null:
return defaultSerializer.Deserialize(reader, objectType);
default:
throw new JsonSerializationException(string.Format("Token \"{0}\" of type {1} was not a JSON integer", reader.Value, reader.TokenType));
}
}
public override bool CanWrite { get { return false; } }
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
public static class JsonExtensions
{
public static bool IsIntegerType(this Type type)
{
type = Nullable.GetUnderlyingType(type) ?? type;
if (type == typeof(long)
|| type == typeof(ulong)
|| type == typeof(int)
|| type == typeof(uint)
|| type == typeof(short)
|| type == typeof(ushort)
|| type == typeof(byte)
|| type == typeof(sbyte)
|| type == typeof(System.Numerics.BigInteger))
return true;
return false;
}
}
请注意,转换器接受像4.00
这样的值作为整数.如果不符合您的需要,可以通过删除JsonToken.Float
的复选框来更改它.
Note the converter accepts values like 4.00
as integers. You can change this by removing the check for JsonToken.Float
if it does not meet your needs.
您可以将其直接应用于模型,如下所示:
You can apply it to your model directly as follows:
public class RootObject
{
[JsonConverter(typeof(StrictIntConverter))]
public int id { get; set; }
public string name { get; set; }
}
或将转换器包含在 JsonSerializerSettings
中以将其应用于所有整数字段:
Or include the converter in JsonSerializerSettings
to apply it to all integral fields:
var settings = new JsonSerializerSettings
{
Converters = { new StrictIntConverter() },
};
var root = JsonConvert.DeserializeObject<RootObject>(json, settings);
最后,要在Web API中全局应用JSON序列化程序设置,请参见例如.
Finally, to apply JSON serializer settings globally in Web API, see for instance here.
这篇关于JSON反序列化-字符串自动转换为Int的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!