.NET Core 2.0中ServiceStack JSON反序列化复杂POCO返回null问题
刚碰到过类似的ServiceStack版本升级后的序列化问题,给你整理下针对性的解决方案:
一、修复JsonServiceClient反序列化返回null的问题
浏览器和Ajax调用正常,但JsonServiceClient返回null,大概率是v5.0.2版本后ServiceStack的JSON序列化器规则变化导致的,按下面的步骤排查:
确保POCO有公共无参构造函数
ServiceStack的JSON序列化器在v5.0.2之后对构造函数的检查更严格,如果你的复杂POCO只有带参数的构造函数,序列化器无法实例化对象,最终返回null。给每个需要反序列化的类补上无参构造函数就行:public class Order { // 必须添加公共无参构造函数 public Order() {} public string OrderId { get; set; } public List<OrderItem> Items { get; set; } }检查属性的可访问性
所有需要被反序列化的属性必须是公共可读写的(public get; set;),如果是只读或者私有属性,序列化器没法赋值,也会导致整个对象为null。调整客户端序列化配置
v5.0.2之后默认启用了严格类型检查,你可以尝试在客户端关闭这个特性,或者开启空值包含:var client = new JsonServiceClient("https://your-api-url.com") { JsonSerializer = new JsonSerializer { StrictMode = false, IncludeNullValues = true } }; var response = client.Get<OrderResponse>("/api/orders");匹配JSON字段和POCO属性名
有时候浏览器返回的JSON字段名和客户端POCO的属性名不匹配(比如大小写、下划线命名 vs 驼峰命名),可以用[DataMember]特性手动映射:public class OrderItem { [DataMember(Name = "product_id")] public string ProductId { get; set; } }
二、解决ProtobufServiceClient的嵌套列表不支持问题
Protobuf本身对嵌套集合的支持就有限,ServiceStack的Protobuf序列化器明确不允许嵌套或锯齿状的列表/数组(比如List<List<T>>或者T[][]),你需要调整POCO结构来适配:
用包装类替代直接嵌套列表
把内层的列表包装成一个单独的实体类,这样就能避开Protobuf的限制。举个例子:// 原来的错误写法(不支持) public class BadResponse { public List<List<Product>> ProductGroups { get; set; } } // 修改后的正确写法(支持) public class GoodResponse { public List<ProductGroup> ProductGroups { get; set; } } public class ProductGroup { public List<Product> Products { get; set; } }添加Protobuf序列化特性
别忘了给所有需要序列化的类和属性加上[ProtoContract]和[ProtoMember]特性,并且成员编号要唯一:[ProtoContract] public class ProductGroup { [ProtoMember(1)] public List<Product> Products { get; set; } } [ProtoContract] public class Product { [ProtoMember(1)] public string ProductId { get; set; } }
总结
这两个问题都是ServiceStack v5.0.2版本升级后序列化器规则变化带来的,调整POCO的结构和配置就能解决:优先处理无参构造函数和属性可访问性解决JSON反序列化的null问题,通过包装嵌套集合解决Protobuf的不支持问题。
内容的提问来源于stack exchange,提问作者Suresh Balasubramanian

