Json是现代化应用系统最常用的数据交换格式,NewLife.Core 从2010年开始就独立实现了Json序列化和反序列化。准确的说,NewLife.Core 内置实现了三套Json序列化,用于不同场景。
Nuget包:NewLife.Core
源码:https://github.com/NewLifeX/X/tree/master/NewLife.Core/Serialization/Json
视频:https://www.bilibili.com/video/BV1Xd4y1i7ga
最佳实践
任意对象转Json字符串,Nuget引用包 NewLife.Core
using namespace NewLife.Serialization;
var obj = new { Name = "NewLife", Description = "新生命团队" };
var str = obj.ToJson(true);快速扩展
在NewLife系列组件中,随处可见ToJson/ToJsonEntity,正是由该模块的 NewLife.Serialization.JsonHelper 实现!
JsonHelper 实现为扩展方法,命名空间是 NewLife.Serialization,主要方法如下:
// 写入对象,得到Json字符串 String ToJson(this Object value, Boolean indented = false); String ToJson(this Object value, Boolean indented, Boolean nullValue, Boolean camelCase); // 从Json字符串中读取对象 Object ToJsonEntity(this String json, Type type); T ToJsonEntity<T>(this String json); // 格式化Json文本 String Format(String json); // Json类型对象转换实体类 T Convert<T>(Object obj);
ToJson可把常见对象序列化为Json字符串。indented用于生成带缩进的可读性很好的Json文本,一般只用于调试。
ToJsonEntity则是把Json字符串反序列化到目标类型,得到目标对象。
这些扩展方法基于IJsonHost接口实现,用户可以自定义IJsonHost并修改JsonHelper.Default即可改变内部序列化行为。
Json分析器
在WebApi接口对接时,简单的接口可能不想写Model类,而又需要拿到Json结果中的值。或者接口返回具有多种模式,例如正常返回和异常返回不同。这些场景,都可以利用Json分析器JsonParser,把Json字符串解析为IDictionary<String,Object> 和 IList<Object> 构成的字典树。理论上,任意Json数据都可以用 IDictionary<String,Object> 和 IList<Object> 嵌套来表示。
例如星尘的客户端接口:
var rs = client.Get<IDictionary<String, Object>>("Config/GetAll", new
{
appId = AppId,
secret = Secret,
scope = Scope,
version = _version,
});
// 增强版返回
if (rs.TryGetValue("configs", out var obj) && obj is IDictionary<String, Object> configs)
{
var ver = rs["version"].ToInt(-1);
if (ver > 0) _version = ver;
return configs;
}传参使用匿名对象,内部借助ToJson序列化为字符串,返回时直接要IDictionary<String, Object>,然后取下一级对象,内部正是由JsonParser提供支持。
该接口的返回数据是这样的:

这是很常见的JsonApi返回格式,code不是0或200时,代表异常响应,data中可能就不是预期的格式了。
JsonParser 的用法非常简单,直接传入json字符串new实例化,然后Decode。或者静态Decode。
public JsonParser(String json);
public Object Decode();
/// <summary>解码</summary>
/// <param name="json"></param>
/// <returns></returns>
public static IDictionary<String, Object> Decode(String json)
{
var parser = new JsonParser(json);
return parser.ParseValue() as IDictionary<String, Object>;
}基于轻量级理念设计,JsonParser性能非常给力。
Json读写器
快速扩展的ToJson由 JsonWriter 实现,主要成员如下:
/// <summary>使用UTC时间。默认false</summary>
public Boolean UseUTCDateTime { get; set; }
/// <summary>使用小写名称</summary>
public Boolean LowerCase { get; set; }
/// <summary>使用驼峰命名</summary>
public Boolean CamelCase { get; set; }
/// <summary>忽略空值。默认false</summary>
public Boolean IgnoreNullValues { get; set; }
/// <summary>忽略只读属性。默认false</summary>
public Boolean IgnoreReadOnlyProperties { get; set; }
/// <summary>忽略注释。默认true</summary>
public Boolean IgnoreComment { get; set; } = true;
/// <summary>忽略循环引用。遇到循环引用时写{},默认true</summary>
public Boolean IgnoreCircle { get; set; } = true;
/// <summary>枚举使用字符串。默认false使用数字</summary>
public Boolean EnumString { get; set; }
/// <summary>缩进。默认false</summary>
public Boolean Indented { get; set; }
/// <summary>智能缩进,内层不换行。默认false</summary>
public Boolean SmartIndented { get; set; }
/// <summary>最大序列化深度。超过时不再序列化,而不是抛出异常,默认5</summary>
public Int32 MaxDepth { get; set; } = 5;
/// <summary>写入对象</summary>
/// <param name="value"></param>
public void Write(Object value);
/// <summary>获取结果</summary>
/// <returns></returns>
public String GetString();实例化JsonWriter后,直接Write对象,然后GetString取结果。足够简单,而又具备常见功能,不会拖泥带水!
快速扩展的ToJsonEntity由 JsonReader 实现,主要成员如下:
/// <summary>是否使用UTC时间</summary>
public Boolean UseUTCDateTime { get; set; }
/// <summary>服务提供者</summary>
public IServiceProvider Provider { get; set; } = ObjectContainer.Provider;
/// <summary>读取Json到指定类型</summary>
/// <typeparam name="T"></typeparam>
/// <param name="json"></param>
/// <returns></returns>
public T Read<T>(String json);
/// <summary>读取Json到指定类型</summary>
/// <param name="json"></param>
/// <param name="type"></param>
/// <returns></returns>
public Object Read(String json, Type type);实例化JsonReader后,直接Read读取结果。属性中的Provider很强大,支持Read的模型类带有接口成员或抽象成员,JsonReader内部将借助IServiceProvider得到该接口类或抽象类的真实实现。
例如性能跟踪器中有这么一个接口:
/// <summary>跟踪片段构建器</summary>
public interface ISpanBuilder
{
#region 属性
/// <summary>跟踪器</summary>
ITracer Tracer { get; }
/// <summary>操作名</summary>
String Name { get; set; }
/// <summary>开始时间。Unix毫秒</summary>
Int64 StartTime { get; set; }
/// <summary>结束时间。Unix毫秒</summary>
Int64 EndTime { get; set; }
/// <summary>采样总数</summary>
Int32 Total { get; }
/// <summary>错误次数</summary>
Int32 Errors { get; }
/// <summary>总耗时。所有请求耗时累加,单位ms</summary>
Int64 Cost { get; }
/// <summary>最大耗时。单位ms</summary>
Int32 MaxCost { get; }
/// <summary>最小耗时。单位ms</summary>
Int32 MinCost { get; }
/// <summary>正常采样</summary>
IList<ISpan> Samples { get; }
/// <summary>异常采样</summary>
IList<ISpan> ErrorSamples { get; }
#endregion
#region 方法
/// <summary>开始一个Span</summary>
/// <returns></returns>
ISpan Start();
/// <summary>完成Span</summary>
/// <param name="span"></param>
void Finish(ISpan span);
#endregion
}其中的Samples和ErrorSamples类型是IList<ISpan>,ISpan也是接口。星尘在接收数据时,不想再搞一堆实现该接口的模型类,希望能够直接利用默认的DefaultSpanBuilder。因此,可以有以下写法:
var builder = "xxx".ToJsonEntity<ISpanBuilder>();
标准Json序列化
标准版Json序列化框架 NewLife.Serialization.Json 提供了足够强大的可扩展能力,支持各种定制。然而随着Json用法日趋标准化,在序列化上进行定制的意义越来越小!
Json类主要成员如下:
Boolean Write(Object value, Type type = null); Object Read(Type type); T Read<T>(); Boolean TryRead(Type type, ref Object value);
总结
推荐使用 ToJson/ToJsonEntity/JsonParser ,在.NETCore新项目中,推荐使用 System.Text.Json !