欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Asp.Net Core 轻松学-实现跨平台的自定义Json数据包

程序员文章站 2022-03-26 14:13:39
在前后端分离的业务开发中,我们总是需要返回各种各样的数据包格式,一个良好的 json 格式数据包是我们一贯奉行的原则,下面就利用 Json.Net 来做一个简单具有跨平台的序列化数据包实现类 ......

前言

    在前后端分离的业务开发中,我们总是需要返回各种各样的数据包格式,一个良好的 json 格式数据包是我们一贯奉行的原则,下面就利用 json.net 来做一个简单具有跨平台的序列化数据包实现类。

1. 应用 json.net

  • 1.1 首先在项目中引用 nuget 包

Asp.Net Core 轻松学-实现跨平台的自定义Json数据包

  • 1.2 编写一个 jsonreturn 结果包装类,继承自 contentresult ,并重写 contentresult 方法 executeresult(actioncontext context)
   public partial class jsonreturn : contentresult
    {
        public int code { get; protected set; }
        public string message { get; protected set; }
        public hashtable data { get; protected set; } = new hashtable();
        public bool success { get { return this.code == 0; } }

        public jsonreturn(int code, string message) { this.code = code; this.setmessage(message); }

        public jsonreturn setmessage(string value) { this.message = value; return this; }

        public jsonreturn setdata(params object[] value)
        {
            this.data.clear();
            return this.appenddata(value);
        }

        public jsonreturn appenddata(params object[] value)
        {
            if (value?.length < 2)
                return this;

            for (int a = 0; a < value.length; a += 2)
            {
                if (value[a] == null) continue;
                this.data[value[a]] = a + 1 < value.length ? value[a + 1] : null;
            }
            return this;
        }

        private void tojson(actioncontext context)
        {
            this.contenttype = "text/json;charset=utf-8;";
            this.content = jsonconvert.serializeobject(this);
        }

        public override task executeresultasync(actioncontext context)
        {
            tojson(context);
            return base.executeresultasync(context);
        }

        public override void executeresult(actioncontext context)
        {
            tojson(context);
            base.executeresult(context);
        }

        /// <summary>
        /// 成功 0
        /// </summary>
        public static jsonreturn 成功 { get { return new jsonreturn(0, "成功"); } }

        /// <summary>
        ///  失败 500
        /// </summary>
        public static jsonreturn 失败 { get { return new jsonreturn(500, "失败"); } }
    }
  • 在 jsonreturn 类中,定义了一个存储业务数据对象的 hashtable 对象,在接口中可以往该对象中写入需要序列化的数据,并重写了 contentresult 的 executeresultasync 和 executeresult 方法,在方法内实现 jsonresult 对象的序列化,最后提供了两个静态属性方便调用;在 jsonreutrn 类中,最重要的是定义了成功和失败的 code ,默认 0 =成功,500=失败,这样就约定了所有客户端都强制使用该协议,完成了标准的统一。

  • 1.3 在控制器中将此对象返回

        [httpget]
        public actionresult get()
        {
            userinfo info = new userinfo()
            {
                age = 22,
                gender = true,
                name = "ron.lang",
                regtime = datetime.now
            };
            return jsonreturn.成功.setdata("detail", info);
        }
  • 1.4 运行程序,得到如下内容
{
  "code": 0,
  "message": "成功",
  "data": {
    "detail": {
      "name": "ron.lang",
      "gender": true,
      "age": 22,
      "regtime": "2018-12-02t16:27:17.3289028+08:00"
    }
  }
}

2. 改造

  • 2.1 上面的结果还可以接受,只是有一点小瑕疵,比如 bool 类型和字段名称大小写的问题,以及时间格式,都不是太友好,对于跨平台来说,会存在一些问题,下面我们改造一下,使得输出的字段名称全部消息,bool 类型转换为数字 0/1,时间转换为 unix 格式;首先创建 3 个自定义 json 序列化类

  • 2.2 lowercasecontractresolver.cs 转换字段名称为小写,该类非常简单,仅有一行核心代码

public class lowercasecontractresolver : defaultcontractresolver
{
    protected override string resolvepropertyname(string propertyname)
    {
        return propertyname.tolower();
    }
}
  • 2.3 booleanconverter.cs 将 bool 类型转换为数字 0/1
public class booleanconverter : jsonconverter
{
    public override bool canconvert(type objecttype)
    {
        return objecttype == typeof(bool) || objecttype == typeof(nullable<bool>);
    }

    public override object readjson(jsonreader reader, type objecttype, object existingvalue, jsonserializer serializer)
    {
        if (reader.value == null)
            return null;

        return convert.toboolean(reader.value);
    }

    public override void writejson(jsonwriter writer, object value, jsonserializer serializer)
    {
        if (value == null)
            writer.writenull();
        else
        {
            uint32 val = convert.touint32(convert.toboolean(value));
            writer.writevalue(val);
        }
    }
}
  • 2.4 datetimeconverter.cs unix 时间格式转换类
public class datetimeconverter : datetimeconverterbase
{
    public static datetime greenwich_mean_time = timezoneinfo.converttime(new datetime(1970, 1, 1), timezoneinfo.local);
    public override bool canconvert(type objecttype)
    {
        return objecttype == typeof(datetime) || objecttype == typeof(nullable<datetime>);
    }

    public override object readjson(jsonreader reader, type objecttype, object existingvalue, jsonserializer serializer)
    {
        if (reader.value == null)
            return null;

        if (canconvert(objecttype))
        {
            if (string.isnullorempty(reader.value.tonullorstring()))
                return reader.value;

            if (reader.value is string)
            {
                if (datetime.tryparse(reader.value.tostring(), out datetime dt))
                    return dt;
                else
                    return reader.value;
            }
            else
                return new datetime(greenwich_mean_time.ticks + convert.toint64(reader.value) * 10000).tolocaltime();
        }
        else
            return reader.value;
    }

    public override void writejson(jsonwriter writer, object value, jsonserializer serializer)
    {
        if (value == null)
            writer.writenull();
        else
        {
            long val = 0;
            if (value.gettype() == typeof(datetime))
            {
                datetime dt = convert.todatetime(value);
                val = (dt.touniversaltime().ticks - greenwich_mean_time.ticks) / 10000;
            }
            else
                val = convert.toint64(value);

            writer.writevalue(val);
        }
    }
}
  • 2.5 最后一步,全局注册 jsonsettings 到系统中,打开 startup.cs 文件,在 startup 方法中写入以下内容
        public startup(iconfiguration configuration, ihostingenvironment env)
        {
            jsonconvert.defaultsettings = () =>
            {
                var st = new jsonserializersettings
                {
                    formatting = formatting.indented
                };

                st.converters.add(new booleanconverter());
                st.converters.add(new datetimeconverter());
                st.contractresolver = new lowercasecontractresolver();

                return st;
            };
        }
  • 2.6 运行程序,接口输出以下内容,完成
{
  "code": 0,
  "message": "成功",
  "data": {
    "detail": {
      "name": "ron.lang",
      "gender": 1,
      "age": 22,
      "regtime": 1543739815980
    }
  }
}

结语

通过继承 contentresult 实现自定义的序列化数据包,这是刚需;为了实现跨平台的要求,我们还自定义 jsonsettings 实现各种类型的自定义转换,在实际项目开发中,这是非常有用的。

代码下载

https://files.cnblogs.com/files/viter/ron.jsontest.zip