ServiceStack如何正确序列化Dictionary<string,object>嵌套对象
问题描述
待处理的嵌套JSON数据结构示例如下:
"event-data": { "event": "opened", "timestamp": 1529006854.329574, "id": "DACSsAdVSeGpLid7TN03WA", "delivery-status": { "title": "success" } }
业务代码中定义的对应数据结构为:
//Structure public List<Dictionary<string, object>> EventData { get; set; } = new List<Dictionary<string, object>>();
当前使用的序列化实现代码为:
var json = ServiceStack.Text.JsonSerializer.SerializeToString(request.EventData);
使用上述方式执行序列化时,仅根层级对象可被正常转换为JSON格式,所有子对象会被大量\n、\t转义符包裹,被直接处理为扁平化字符串,无法生成结构正确的嵌套JSON。需要找到ServiceStack中实现原生嵌套JSON输出的正确且性能最优的实现方式。
最优实现方案
问题根源:ServiceStack.Text默认对Dictionary<string, object>中类型为object的嵌套值执行ToString()逻辑,不会递归序列化嵌套的复杂结构,因此会出现带大量转义符的扁平化字符串结果。按性能从高到低,可选择以下方案:
- 性能最优方案:替换为强类型POCO结构
强类型序列化是ServiceStack.Text性能最高的序列化路径,无运行时类型推断开销,比弱类型序列化性能高30%以上,且完全不会出现转义问题。
对应示例结构的POCO定义如下:
替换后直接调用原有using System.Runtime.Serialization; // 对应嵌套的delivery-status结构 public class DeliveryStatus { public string title { get; set; } } // 对应单条event-data结构 public class EventDataItem { public string @event { get; set; } public double timestamp { get; set; } public string id { get; set; } [DataMember(Name = "delivery-status")] public DeliveryStatus delivery_status { get; set; } } // 业务类属性修改为强类型集合 public List<EventDataItem> EventData { get; set; } = new List<EventDataItem>();JsonSerializer.SerializeToString()方法,即可输出结构正确的原生嵌套JSON。 - 次优方案(必须保留弱类型结构时选择):全局配置弱类型序列化规则
如果业务场景无法替换为强类型结构,仅需在程序启动时执行一次全局配置,即可让序列化器递归处理嵌套的Dictionary结构:
配置完成后原有序列化代码无需修改,即可输出无转义符的嵌套JSON,该方案仅比强类型方案多10%左右的运行时类型检查开销,性能远高于其他动态序列化方案。// 应用初始化阶段执行,全局生效 JsConfig.ConvertObjectTypesIntoStringDictionary = true; JsConfig.ExcludeTypeInfo = true;
注意:不要使用先序列化为字符串再反序列化为JsonObject、再二次序列化的方案,该方案会产生双倍序列化/反序列化开销,性能损耗超过50%,且容易出现字段类型转换错误。
内容的提问来源于stack exchange,提问作者Steve McNiven-Scott
相关产品推荐
相关产品推荐

