无法将 JSON 数组反序列化为类型 - Json.NET

Posted

技术标签:

【中文标题】无法将 JSON 数组反序列化为类型 - Json.NET【英文标题】:Cannot deserialize JSON array into type - Json.NET 【发布时间】:2012-03-16 05:03:23 【问题描述】:

我正在尝试将 json 数据反序列化为模型类,但我失败了。这是我的工作:

    public CountryModel GetCountries() 

        using (WebClient client = new WebClient()) 

            var result = client.DownloadString("http://api.worldbank.org/incomeLevels/LIC/countries?format=json");

            var output = JsonConvert.DeserializeObject<List<CountryModel>>(result);

            return output.First();
        
    

这是我的模型的样子:

public class CountryModel

    public int Page  get; set; 
    public int Pages  get; set; 
    public int Per_Page  get; set; 
    public int Total  get; set; 

    public List<Country> Countries  get; set; 


public class Country

    public int Id  get; set; 
    public string Iso2Code  get; set; 
    public string Name  get; set; 
    public Region Region  get; set; 


public class Region

    public int Id  get; set; 
    public string Value  get; set; 

你可以看到我在这里得到的 Json:http://api.worldbank.org/incomeLevels/LIC/countries?format=json

这是我得到的错误:

无法将 JSON 数组反序列化为“Mvc4AsyncSample.Models.CountryModel”类型。第 1 行,位置 1。

【问题讨论】:

这似乎不是一个好的 JSON 表示。如果你使用 XML 格式可能会更好。 是的,我想是的。他们将单个对象放入数组中。我认为它不应该在那里。有什么可行的方法吗? XML 更加简洁,我会这样做:api.worldbank.org/incomeLevels/LIC/countries?format=xml @PaulTyng 我认为,AFAIK,Json.NET 序列化比 .NET XML 序列化快得多。这就是我坚持使用 JSON 的原因。但我不确定我在这里是否 100% 正确。 @tugberk 啊,我明白了,如果您关心速度,尽管您可能想查看其他 JSON 库:theburningmonk.com/2011/08/performance-test-json-serializers(或 code.google.com/p/protobuf-net) 【参考方案1】:

你要写一个自定义的JsonConverter

    public class CountryModelConverter : JsonConverter
    

        public override bool CanConvert(Type objectType)
        
            if (objectType == typeof(CountryModel))
            
                return true;
            

            return false;
        

        public override object ReadJson(JsonReader reader, Type objectType
            , object existingValue, JsonSerializer serializer)
        
            reader.Read(); //start array
            //reader.Read(); //start object
            JObject obj = (JObject)serializer.Deserialize(reader);

            //"page":1,"pages":1,"per_page":"50","total":35
            var model = new CountryModel();

            model.Page = Convert.ToInt32(((JValue)obj["page"]).Value);
            model.Pages = Convert.ToInt32(((JValue)obj["pages"]).Value);
            model.Per_Page = Int32.Parse((string) ((JValue)obj["per_page"]).Value);
            model.Total = Convert.ToInt32(((JValue)obj["total"]).Value);

            reader.Read(); //end object

            model.Countries = serializer.Deserialize<List<Country>>(reader);

            reader.Read(); //end array

            return model;
        

        public override void WriteJson(JsonWriter writer, object value
            , JsonSerializer serializer)
        
            throw new NotImplementedException();
        
    

并使用该转换器标记CountryModel(我还必须将一些int 切换为string):

    [JsonConverter(typeof(CountryModelConverter))]
    public class CountryModel
    
        public int Page  get; set; 
        public int Pages  get; set; 
        public int Per_Page  get; set; 
        public int Total  get; set; 

        public List<Country> Countries  get; set; 
    

    public class Country
    
        public string Id  get; set; 
        public string Iso2Code  get; set; 
        public string Name  get; set; 
        public Region Region  get; set; 
    

    public class Region
    
        public string Id  get; set; 
        public string Value  get; set; 
    

那么你应该可以像这样反序列化:

var output = JsonConvert.DeserializeObject<CountryModel>(result);

【讨论】:

你不能通过使用serializer.Deserialize&lt;CountryModel&gt;(reader) 来简化反序列化CountryModel 的属性吗? 如果您只需要阅读,svick 的答案会更好,JsonConverter 只有在您必须双向使用时才真正需要。 @svick 我想了想,问题是CountryModel 有这个属性,所以它进入了无限循环,如果对象模型改变了,它会被简化,但我试图保持他的对象模型。 对,我没想到。【参考方案2】:

这看起来像是(不是很好)用 JSON 表示 XML 的尝试。 JSON 如下所示:

[
  
    "page": 1,
    …
  ,
  [
    
      "id": "AFG",
      "name": "Afghanistan",
      …
    ,
    
      "id": "BDI",
      "name": "Burundi",
      …
    ,
    …
  ]
]

虽然一个合理的 JSON(顺便说一句会很好地映射到您的模型)看起来像这样:


  "page": 1,
  …,
  "countries": [
    
      "id": "AFG",
      "name": "Afghanistan",
      …
    ,
    
      "id": "BDI",
      "name": "Burundi",
      …
    ,
    …
  ]

如果您确定要使用 JSON(而不是 XML),您可以先将 JSON 反序列化为 JSON.NET 的对象模型,然后将其反序列化为您的模型:

var json = client.DownloadString("http://api.worldbank.org/incomeLevels/LIC/countries?format=json");

var array = (JArray)JsonConvert.DeserializeObject(json);

var serializer = new JsonSerializer();

var countryModel = serializer.Deserialize<CountryModel>(array[0].CreateReader());

countryModel.Countries = serializer.Deserialize<List<Country>>(array[1].CreateReader());

return countryModel;

不要忘记将您的 Id 属性更改为 string,因为它们就是这样。

【讨论】:

比我的版本简单得多,很好,不知道你可以创建阅读器的内置对象。【参考方案3】:

您的模型与 JSON 结构不匹配。您似乎缺少最后 6 个属性。


"id": "AFG",
"iso2Code": "AF",
"name": "Afghanistan",
"region": 
    "id": "SAS",
    "value": "South Asia"
,
"adminregion": 
    "id": "SAS",
    "value": "South Asia"
,
"incomeLevel": 
    "id": "LIC",
    "value": "Low income"
,
"lendingType": 
    "id": "IDX",
    "value": "IDA"
,
"capitalCity": "Kabul",
"longitude": "69.1761",
"latitude": "34.5228"

【讨论】:

这不会影响反序列化过程。

以上是关于无法将 JSON 数组反序列化为类型 - Json.NET的主要内容,如果未能解决你的问题,请参考以下文章

无法将当前 JSON 数组(例如 [1,2,3])反序列化为类型“ConsoleAppTest01.Location”,因为该类型需要 JSON 对象

WinForms 错误无法将当前 JSON 数组(例如 [1,2,3])反序列化为类型

无法将 JSON 数组(例如 [1,2,3])反序列化为类型 ' ',因为类型需要 JSON 对象(例如 "name":"value")才能正确反序列化

无法将 JSON 数组(例如 [1,2,3])反序列化为类型 ' ',因为类型需要 JSON 对象(例如 "name":"value")才能正确反序列化

无法将 JSON 数组(例如 [1,2,3])反序列化为类型 ' ',因为类型需要 JSON 对象(例如 "name":"value")来反序列化 withGe

无法将当前 JSON 数组(例如 [1,2,3])反序列化为具有复杂和嵌套对象的类型