Asp.Net Core 轻松学-实现跨平台的自定义Json数据包
程序员文章站
2022-06-27 21:44:01
在前后端分离的业务开发中,我们总是需要返回各种各样的数据包格式,一个良好的 json 格式数据包是我们一贯奉行的原则,下面就利用 Json.Net 来做一个简单具有跨平台的序列化数据包实现类 ......
前言
在前后端分离的业务开发中,我们总是需要返回各种各样的数据包格式,一个良好的 json 格式数据包是我们一贯奉行的原则,下面就利用 json.net 来做一个简单具有跨平台的序列化数据包实现类。
1. 应用 json.net
- 1.1 首先在项目中引用 nuget 包
- 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 实现各种类型的自定义转换,在实际项目开发中,这是非常有用的。