Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/278.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# JsonConvert.DeserializeObject<&燃气轮机;(字符串)返回$id属性的空值_C#_Json.net_Webclient - Fatal编程技术网

C# JsonConvert.DeserializeObject<&燃气轮机;(字符串)返回$id属性的空值

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"

我正在使用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; }
}
公共类表单定义列表
{
[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;
}