我正在使用System.Net.WebClient.DownloadString下载JSON。我收到了有效回复:
{
"FormDefinition": [
{
"$id":"4",
"Class":558,
"ClassDisplayLabel":"Punchworks",
"Name":"Punchworks Form"
},
{
"$id":"6",
"Class":558,
"ClassDisplayLabel":"Punchworks",
"Name":"Punchworks Form test second"
},
{
"$id":"46",
"Class":558,
"ClassDisplayLabel":"Punchworks",
"Name":"any_Name"
},
{
"$id":"47",
"Class":558,
"ClassDisplayLabel":"Punchworks",
"Name":"Punchworks Form test second"
},
{
"$id":"49",
"Class":558,
"ClassDisplayLabel":"Punchworks",
"Name":"Testing Name ??´????? ???? ACEeišuu { [ ( ~ ! @ # "
},
{
"$id":"50",
"Class":558,
"ClassDisplayLabel":"Punchworks",
"Name":"something new"
},
{
"$id":"56",
"Class":558,
"ClassDisplayLabel":"Punchworks",
"Name":"Testing Name руÌÑÑкий 汉è¯æ¼¢èªž ĄČĘėįšųū { [ ( ~ ! @ # "
},
{
"$id":"57",
"Class":558,
"ClassDisplayLabel":"Punchworks",
"Name":"Test Name"
},
{
"$id":"58",
"Class":558,
"ClassDisplayLabel":"Punchworks",
"Name":"Unique Name - 12/16/2013 12:59:29 PM"
},
{
"$id":"59",
"Class":558,
"ClassDisplayLabel":"Punchworks",
"Name":"Unique Name - 12/16/2013 1:01:18 PM"
},
{
"$id":"60",
"Class":558,
"ClassDisplayLabel":"Punchworks",
"Name":"Unique Name - 12/16/2013 1:40:44 PM"
},
{
"$id":"61",
"Class":558,
"ClassDisplayLabel":"Punchworks",
"Name":"Unique Name - 12/16/2013 1:43:46 PM"
},
{
"$id":"62",
"Class":558,
"ClassDisplayLabel":"Punchworks",
"Name":"Unique Name - 12/16/2013 1:48:21 PM"
},
{
"$id":"63",
"Class":558,
"ClassDisplayLabel":"Punchworks",
"Name":"Unique Name - 12/16/2013 1:57:00 PM"
},
{
"$id":"64",
"Class":558,
"ClassDisplayLabel":"Punchworks",
"Name":"Unique Name - 12/16/2013 1:57:53 PM"
},
{
"$id":"65",
"Class":558,
"ClassDisplayLabel":"Punchworks",
"Name":"Unique Name - 12/16/2013 1:58:46 PM"
},
{
"$id":"79",
"Class":558,
"ClassDisplayLabel":"Punchworks",
"Name":"Testing Name1211"
},
{
"$id":"80",
"Class":558,
"ClassDisplayLabel":"Punchworks",
"Name":"Testing Name1211"
},
{
"$id":"81",
"Class":558,
"ClassDisplayLabel":"Punchworks",
"Name":"any_nami"
},
{
"$id":"90",
"Class":558,
"ClassDisplayLabel":"Punchworks",
"Name":"Test_something3"
},
{
"$id":"91",
"Class":558,
"ClassDisplayLabel":"Punchworks",
"Name":"Test_something4"
}]
}
这是我的模特:
public class FormDefinitionList
{
[JsonProperty("FormDefinition")]
public List<FormDefinition> FormDefinitions { get; set; }
}
public class FormDefinition
{
[JsonProperty ("$id")]
public string Id { get; set; }
[JsonProperty ("Class")]
public int Class { get; set; }
[JsonProperty ("ClassName")]
public string ClassName { get; set; }
[JsonProperty ("ClassDisplayLabel")]
public string ClassDisplayLabel { get; set; }
[JsonProperty ("Definition")]
public string Definition { get; set; }
[JsonProperty ("Name")]
public string Name { get; set; }
}
当我这样做时,一切都有效:
string response = "json as above";
FormDefinitionList root = JsonConvert.DeserializeObject<FormDefinitionList> (response);
除了Id($ id)属性始终为null。起初我试图弄清楚我从服务器回来的美元符号是不同的,但事实并非如此。我不知道从哪里开始,所以有什么想法吗?
提前致谢。
注意:如果我尝试使用JavaScriptSerializer之类的方式进行反序列化,它可以完美地运行,所以我很确定我的模型或JSON.net出了问题。可能是错的。
答案 0 :(得分:11)
Json.Net通常使用$id
和$ref
作为元数据来保存JSON中的对象引用。因此,当它看到$id
时,它假定该属性不是实际JSON属性集的一部分,而是内部标识符。因此,它不会填充对象上的Id
属性,即使您包含一个[JsonProperty]
属性指示它应该。
<强>更新强>
从Json.Net版本6.0.4开始,有一个新设置可以指示反序列化器将这些“元数据”属性视为普通属性而不是消耗它们。您需要做的就是将MetadataPropertyHandling
设置为Ignore
,然后照常反序列化。
var settings = new JsonSerializerSettings();
settings.MetadataPropertyHandling = MetadataPropertyHandling.Ignore;
var obj = JsonConvert.DeserializeObject<FormDefinitionList>(json, settings);
在6.0.4版之前,需要一种解决方法来解决此问题。本答案的其余部分讨论了可能的解决方法。如果您使用的是6.0.4或更高版本,则不需要解决方法,现在可以停止阅读。
我可以看到的最简单的解决方法是在反序列化之前在JSON上用"$id"
(包括引号)替换"id"
,正如@Carlos Coelho建议的那样。由于您必须对每个响应执行此操作,如果您采用此路由,我建议您使用简单的帮助方法来避免代码重复,例如:
public static T Deserialize<T>(string json)
{
return JsonConvert.DeserializeObject<T>(json.Replace("\"$id\"", "\"id\""));
}
但是,既然你在评论中说过你不是那么热衷于使用字符串替换的想法,我会调查其他选项。我找到了另一个可能对你有用的替代方案 - 自定义JsonConverter
。转换器背后的想法是它会尝试使用Json.Net的内置反序列化机制来创建和填充对象(无ID),然后从JSON手动检索$id
属性并使用它来填充通过反射在对象上的Id
属性。
以下是转换器的代码:
public class DollarIdPreservingConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(FormDefinition);
}
public override object ReadJson(JsonReader reader, Type objectType,
object existingValue, JsonSerializer serializer)
{
JObject jo = JObject.Load(reader);
object o = jo.ToObject(objectType);
JToken id = jo["$id"];
if (id != null)
{
PropertyInfo prop = objectType.GetProperty("Id");
if (prop != null && prop.CanWrite &&
prop.PropertyType == typeof(string))
{
prop.SetValue(o, id.ToString(), null);
}
}
return o;
}
public override void WriteJson(JsonWriter writer, object value,
JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
我尝试编写转换器,使其适用于具有$id
的任何对象 - 您只需要相应地更改CanConvert
方法,以便为所有类型返回true除FormDefinition
之外,您还需要使用它。
要使用转换器,只需将其实例传递给DeserializeObject<T>
,如下所示:
FormDefinitionList root = JsonConvert.DeserializeObject<FormDefinitionList>(
json, new DollarIdPreservingConverter());
重要提示:您可能想要使用JsonConverter
属性修饰您的课程,而不是将转换器传递到DeserializeObject
来电,但不要这样做 - - 它将导致转换器进入递归循环,直到堆栈溢出。 (有一种方法可以使转换器使用该属性,但您必须重写ReadJson
方法以手动创建目标对象并填充其属性而不是调用jo.ToObject(objectType)
。这是可行的,但有点麻烦。)
请告诉我这是否适合您。
答案 1 :(得分:0)
问题是$符号,因此解决方法是:
从JsonProperty注释中删除$。
[JsonProperty ("id")]
public string Id { get; set; }
在您的代码中,替换特殊字符$
string response = "json as above";
FormDefinitionList root = JsonConvert.DeserializeObject<FormDefinitionList> (response.Replace("$id","id"));
编辑为@BrianRogers建议
答案 2 :(得分:0)
这个答案为我修复了$ id / $ ref问题:Json.Net adding $id to EF objects despite setting PreserveReferencesHandling to "None"
在DefaultContractResolver / IContractResolver的实现中,添加此内容;
public override JsonContract ResolveContract(Type type) {
var contract = base.ResolveContract(type);
contract.IsReference = false;
return contract;
}
编辑:这将删除$ id。