我有一个返回json数据的webservice。我无法控制服务器端生成的json。
我像这样反序列化json:
JsonConvert.DeserializeObject<OuterObject>(jsonString);
问题是有内部对象嵌入(有很多嵌套的内部对象)。我没有兴趣在我的应用程序中建模它们。
json-data是这样的:
{
id : "xyz",
name : "Some Object",
properties : {
prop_1 : "foo",
prop_2 : "bar"
},
inner_object : {
id : "abc$1",
name : "Inner Object Name",
....
// a whole lot of stuff here
// with more embedded objects
....
}
}
我想将外部对象建模为一个简单的POCO,其中内部对象仅由(String) id引用,而不是对象引用。
public class Outer
{
public String Id { get; internal set; }
public String Name { get; internal set; }
public Dictionary<String,String> Properties { get; internal set; }
// Just keep the InnerObject Id, no real reference to an instance
public String InnerObjectId { get; set; }
}
我想我可以写一个JsonOuterObject版本与一个真正的对象引用JsonInnerObject和构造我真正的OuterObject从那里,扔掉其他对象之后…但那太差劲了。(我不想在这样的提交中看到我的名字)
我在摆弄Json。. NET的IContractResolver(覆盖DefaultContractResolver)现在,但看起来我在这里很长一段时间。
我错过了一些明显的Json。. NET功能在这里为我处理这个?
或者一些指针IContractResolver的哪些方法是有趣的?
EDIT: . net中的POJO显然是POCO。
为outer类型创建自定义JsonConverter可以在反序列化对象时提供很大的灵活性。
这是相当多的工作,但它是值得的努力。特别是如果您无法控制返回的JSON对象,并且您希望在客户端应用程序中对返回的数据进行不同的建模。
JsonConverter实现的核心是重写ReadJson方法
public override object ReadJson(JsonReader reader,
Type objectType,
object existingValue,
JsonSerializer serializer)
JsonReader是一个标记化的数据流。可以这样实现:
public override object ReadJson(JsonReader reader,
Type objectType,
object existingValue,
JsonSerializer serializer)
{
var outer = new Outer()
while (reader.TokenType != JsonToken.EndObject)
{
if (reader.TokenType == JsonToken.PropertyName)
{
var propertyName = reader.Value.ToString();
reader.Read();
switch (propertyName)
{
case "id":
outer.Id = serializer.Deserialize<String>(reader);
break;
case "id":
outer.Properties = serializer.Deserialize<Dictionary<String,String>>(reader);
break;
case "inner_object"
var inner = serializer.Deserialize<Inner>(reader);
outer.InnerObjectId = inner.Id;
break;
[...more cases...]
default:
serializer.Deserialize<object>(reader);
break;
}
reader.Read(); // consume tokens in reader
}
} else {
// throw exception ?
}
}
return outer;
}
你可以用JsonConverterAttribute注释你的Outer对象,或者传递一个长转换器给JsonConverter类的(重载的)Deserialize(String json, params JsonConverter[] converters)方法
一种方法是使用Newtonsoft.Json.Linq和动态类型,因为你实际上是在尝试(或被迫)改变类型安全规则。
public class Outer
{
[JsonProperty(PropertyName = "id")]
public String Id { get; internal set; }
[JsonProperty(PropertyName = "name")]
public String Name { get; internal set; }
[JsonProperty(PropertyName = "properties")]
public Dictionary<String, String> Properties { get; internal set; }
[JsonProperty(PropertyName = "inner_object")]
public dynamic InnerObjectId { get; set; }
}
public void InnerObjectAsDynamic()
{
const string json = @"{""id"":""xyz"",""name"":""Some Object"",""properties"":{""prop_1"":""foo"",""prop_2"":""bar""},""inner_object"":{""id"":""abc$1"",""name"":""Inner Object Name""}}";
var outer = JsonConvert.DeserializeObject<Outer>(json);
var innerObjectJson = outer.InnerObjectId.ToString();
Console.WriteLine(innerObjectJson);
//{
// "id": "abc$1",
// "name": "Inner Object Name"
//}
}
或者,您可以将Outer定义为:
public class Outer
{
[JsonProperty(PropertyName = "id")]
public String Id { get; internal set; }
[JsonProperty(PropertyName = "name")]
public String Name { get; internal set; }
[JsonProperty(PropertyName = "properties")]
public Dictionary<String, String> Properties { get; internal set; }
[JsonProperty(PropertyName = "inner_object")]
public Newtonsoft.Json.Linq.JObject InnerObjectId { get; set; }
}
这对我来说比较干净。祝你好运。