Json.NET特殊处理64位长整型数据
admin
2023-02-15 08:40:05
0

  很多ASP.NET项目,尤其是使用了Ajax的项目,常常需要返回JSON格式的数据。.NET框架从3.5版本开始提供了JSON的序列化和反序列化工具,不过个人感觉不太好用,后来找了第三方的Newtonsoft.Json来用。再后来,在MVC4中,微软已经默认使用Json.NET(Newtonsoft.Json)来处理JSON数据了。


  JavaScript数值精度是32位,如果整数数度超过32位,就会被当作浮点数处理。换句话说,如果从服务端生成的JSON,某个值是64位整数,传到前端JavaScript,再传回服务端,不做任何运算,都可能出现失真。做个实验:


> var a = 123456789012345678
> console.log(a);
123456789012345680


  很要命的一点是,数据库设计中常常会用bigint(64位)整数来作为主键,是一个非常重要而且不能有偏差的数据,比如,一个模型:


// C# 匿名对象
new {
    id: 123456789012345678L,
    name: "James"
};


  转换成JSON输出到前端是:


{"id":123456789012345678,"name":"James"}


  通过Ajax取得的对象输出就有点不妙了


$.getJSON("/api/test").done(function(jo) {
    console.log(jo);
});
// Object {id: 123456789012345680, name: "James"}


  显然,这个对象修改数值之后再传回服务器,就会找不到主键,或者更新成错误的数据,造成一个不易发现的巨大BUG。


  解决办法当然是有的,JavaScript处理字符串的能力非常强,完全可以把服务器端的64位整数处理成字符串类型。不过 Json.NET 默认是把 long 处理成 number 类型的,如果要处理成 string 类型,需要自定义一个JsonConverter。


  考虑到用十六进制表示的整数看起来比较整齐,所以定义一个HexLongConverter来转换long/ulong型数据与16进制表示的字符串。


public class HexLongConverter : JsonConverter
{
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        // 由于CanConvert过滤,数据类型只可能是long或ulong
        // 统一转换成long类型处理
        long v = value is ulong ? (long)(ulong)value : (long)value;
        writer.WriteValue(v.ToString("X16"));
    }
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        // 取得读到的十六进制字符串
        string hex = reader.Value as string;
        // 调用ToInt64扩展将字符串转换成long型
        // ToInt64扩展方法后附
        long v = hex.ToInt64(NumberStyles.HexNumber, 0L);
        // 将v转换成实际需要的类型 ulong 或 long(不转换)
        return typeof (ulong) == objectType ? (object) (ulong) v : v;
    }
    public override bool CanConvert(Type objectType)
    {
        // 只处理long和ulong两种类型的数据
        switch (objectType.FullName)
        {
            case "System.Int64":
            case "System.UInt64":
                return true;
            default:
                return false;
        }
    }
}


  上面的代码用到了一个string的扩展方法ToInt32:


public static class StringExtention
{
    public static int ToInt32(this string me, NumberStyles style,
        int defaultValue)
    {
        int? value = me.ToInt32(style);
        return value == null ? defaultValue : value.Value;
    }
}


  在序列化或反序列化模型的时候,只需要加入HexLongConverter对象作为参数即可:


// 序列化
string json = JsonConvert.SerializeObject(model, new HexLongConverter());
// 反序列化
SomeModal model = JsonConvert.DeserializeObject(json, new HexLongConverter));




相关链接:


[Json.NET]

  • http://json.codeplex.com/

  • http://james.newtonking.com/json



相关内容

热门资讯

电风扇通电不转,但是有电 原因可能是因为电风扇缺油了,可以通过给风扇注油试试,具体的注油方式是能将电机拆下来,然后再对主轴和前...
美的波轮洗衣机通电不转怎么回事 可能是洗衣机顶盖的安全开关损坏,安全开关与可以控制洗衣机的程序,所以需要更换安全开关;可能是异物卡住...
冰箱通电不启动是怎么回事? 可能是电路故障。电源线开路,电源线插头与插座接触不良,启动继电器、过载保护器接线端子脱落或接触不良,...
为什么我家里的燃气热水器通电不... 1、可能是水管内没有水流通过,热水器不工作。2、可能是电池电量低,无法推动点火器。3、可能是水压低造...
冰箱通电后压缩机不启动,但压缩... 1、非常有可能是因为冰箱的压缩机内高压输出缓冲管出现了断裂,造成高压管不排气低压管不吸气的这种状况,...
身高缩了,房子小了,胆子也怯了... 据日经中文网7月24日报道,日本经济长期停滞催生了“不断缩小”的社会倾向,近年来日本人的平均身高持续...
广东省内铁路即将全线停运 作者 | 第一财经 南英今年第12号台风“红霞”已于7月24日凌晨生成,预计25日夜间至26日早晨在...
中美频繁高层互动,菲律宾好自为... 7月24日,菲律宾组织7艘公务船、3艘海警舰、1艘运鱼船,并唆使大量渔船位中国黄岩岛管辖海域非法聚集...
被要求补税2250万欧元的法国... ·贝尔纳·阿尔诺。(LVMH官网)他的“帝国”离不开这个国家的形象加持,而这个国家,也早已吃定了这一...
通派龙湖御潮云上:当极核地段遇... 在2026年的郑州楼市版图中,如果要寻找一个能够同时承载“主城确定性”与“产品革新力”的坐标,通派龙...