C# JsonConvert.DeserializeObject<&燃气轮机;(字符串)返回$id属性的空值
我正在使用System.Net.WebClient.DownloadString下载JSON。我得到了一个有效的答复:C# JsonConvert.DeserializeObject<&燃气轮机;(字符串)返回$id属性的空值,c#,json.net,webclient,C#,Json.net,Webclient,我正在使用System.Net.WebClient.DownloadString下载JSON。我得到了一个有效的答复: { "FormDefinition": [ { "$id":"4", "Class":558, "ClassDisplayLabel":"Punchworks", "Name":"Punchworks Form" }, { "$id":"6", "Class"
{
"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; }
}
公共类表单定义列表
{
[JsonProperty(“FormDefinition”)]
公共列表表单定义{get;set;}
}
公共类表单定义
{
[JsonProperty(“$id”)]
公共字符串Id{get;set;}
[JsonProperty(“类别”)]
公共int类{get;set;}
[JsonProperty(“类名”)]
公共字符串类名{get;set;}
[JsonProperty(“ClassDisplayLabel”)]
公共字符串ClassDisplayLabel{get;set;}
[JsonProperty(“定义”)]
公共字符串定义{get;set;}
[JsonProperty(“名称”)]
公共字符串名称{get;set;}
}
当我这样做时,一切正常:
string response = "json as above";
FormDefinitionList root = JsonConvert.DeserializeObject<FormDefinitionList> (response);
string response=“json如上”;
FormDefinitionList root=JsonConvert.DeserializeObject(响应);
除了Id($Id)属性始终为空之外。起初,我试图弄清楚我从服务器上取回的美元符号是否不同,但事实似乎并非如此。我不知道该怎么办,有什么想法吗
提前谢谢
注意:如果我尝试使用类似JavaScriptSerializer的东西进行反序列化,它工作得很好,所以我相当肯定我的模型或JSON.net有问题。但是可能是错误的。问题在于$符号,因此解决方法是: 从JsonProperty注释中删除$
[JsonProperty ("id")]
public string Id { get; set; }
在代码中,替换特殊字符$
string response = "json as above";
FormDefinitionList root = JsonConvert.DeserializeObject<FormDefinitionList> (response.Replace("$id","id"));
string response=“json如上”;
FormDefinitionList root=JsonConvert.DeserializeObject(response.Replace(“$id”,“id”));
编辑为@BrianRogers建议Json.Net通常使用
$id
和$ref
作为元数据来保存Json中的对象引用。因此,当它看到$id
时,它假定属性不是实际JSON属性集的一部分,而是一个内部标识符。因此,它不会填充对象上的Id
属性,即使您包含了一个[JsonProperty]
属性,指示它应该这样做
更新
从Json.Net版本开始,有一个新的设置,通过该设置,您可以指示反序列化程序将这些“元数据”属性视为普通属性,而不是使用它们。您只需将MetadataPropertyHandling
设置设置为Ignore
,然后像往常一样反序列化
var settings = new JsonSerializerSettings();
settings.MetadataPropertyHandling = MetadataPropertyHandling.Ignore;
var obj = JsonConvert.DeserializeObject<FormDefinitionList>(json, settings);
但是,由于您在评论中说您对使用字符串替换的想法不太感兴趣,因此我考虑了其他选项。我确实找到了另一种可能适合您的替代方案——定制JsonConverter
。转换器背后的想法是,它将尝试使用Json.Net内置的反序列化机制来创建和填充对象(sans 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
方法,以便除了FormDefinition
之外,它还可以为所有需要使用它的类型返回true
要使用转换器,只需将其实例传递给反序列化对象
,如下所示:
FormDefinitionList root = JsonConvert.DeserializeObject<FormDefinitionList>(
json, new DollarIdPreservingConverter());
FormDefinitionList root=JsonConvert.DeserializeObject(
json,新的DollarIdPreservingConverter();
重要提示:您可能会尝试使用JsonConverter
属性来装饰类,而不是将转换器传递到反序列化对象
调用中,但不要这样做——这将导致转换器进入递归循环,直到堆栈溢出。(有一种方法可以让转换器使用属性,但是您必须重写ReadJson
方法来手动创建目标对象并填充其属性,而不是调用jo.ToObject(objectType)
。这是可行的,但有点混乱。)
让我知道这是否适用于您。此答案为我解决了$id/$ref问题: 在DefaultContractResolver/IContractResolver的实现中,添加以下内容:
public override JsonContract ResolveContract(Type type) {
var contract = base.ResolveContract(type);
contract.IsReference = false;
return contract;
}
编辑:这将删除$id。尝试不使用
$
。我建议不要使用特殊字符作为键。@BradM谢谢你的建议。不幸的是,这不是一个选项,因为Api不在我的控制范围之内。虽然可能不推荐使用,但它经常使用,不应该成为这个问题的原因。还有其他想法吗?我想指出,JSON.net应该完全允许使用$。使用String.replace显然不是一个好选项,因为我的响应正文中可能有我想要保留的$字符。@itslitlejohn问题不是$
本身,而是$id
作为一个整体。Json.Net使用这种符号(以及$ref
)来保存Json中的对象引用。因此,当它看到$id
时,它假定属性不是实际JSON属性集的一部分,而是一个内部标识符。在反序列化之前,用“id”
替换“id”
(包括引号字符)字符串可能是一种可行的解决方法。此字符序列不太可能位于实际响应主体中的其他位置。如果我有更多的时间,我会更多地研究这个问题,看看是否有更好的解决办法。@BrianRogers感谢Brian。如果你知道处理此事的好方法,我将不胜感激。我想字符串替换会起作用,但我不想对服务器的每一个响应都这样做。谢谢你付出了额外的努力,Brian。我测试了你的转换器和
public override JsonContract ResolveContract(Type type) {
var contract = base.ResolveContract(type);
contract.IsReference = false;
return contract;
}