简体   繁体   English

无法将当前json对象反序列化为ObservableCollection

[英]Cannot deserialize the current json object into ObservableCollection

(Full error message at the bottom of the post) (帖子底部的完整错误消息)

I am aware that this has already been discussed in several other posts, however, the fixes provided in those posts seems to not work for me. 我知道这已经在其他几篇文章中进行了讨论,但是这些文章中提供的修复程序似乎对我不起作用。

I am providing all my code below. 我在下面提供所有代码。 The deserialization is in the method parseSpellData() . 反序列化在方法parseSpellData()

sample JSON: JSON示例:

{
"_id": "58c9eb75c9e7ce9f7214efaa",
"index": 1,
"name": "Acid Arrow",
"desc": [
    "A shimmering green arrow streaks toward a target within range and bursts in a spray of acid. Make a ranged spell attack against the target. On a hit, the target takes 4d4 acid damage immediately and 2d4 acid damage at the end of its next turn. On a miss, the arrow splashes the target with acid for half as much of the initial damage and no damage at the end of its next turn."
],
"higher_level": [
    "When you cast this spell using a spell slot of 3rd level or higher, the damage (both initial and later) increases by 1d4 for each slot level above 2nd."
],
"page": "phb 259",
"range": "90 feet",
"components": [
    "V",
    "S",
    "M"
],
"material": "Powdered rhubarb leaf and an adder’s stomach.",
"ritual": "no",
"duration": "Instantaneous",
"concentration": "no",
"casting_time": "1 action",
"level": 2,
"school": {
    "url": "http://dnd5eapi.co/api/magic-schools/5",
    "name": "Evocation"
},
"classes": [
    {
        "name": "Wizard",
        "url": "http://dnd5eapi.co/api/classes/12"
    }
],
"subclasses": [
    {
        "url": "http://dnd5eapi.co/api/subclasses/2",
        "name": "Lore"
    },
    {
        "url": "http://dnd5eapi.co/api/subclasses/4",
        "name": "Land"
    }
],
"url": "http://dnd5eapi.co/api/spells/1"
}

Code: 码:

class MainPageViewModel
{
    public ObservableCollection<Spell> availableSpells { get; set; } = new ObservableCollection<Spell>();


    public MainPageViewModel()
    {
        availableSpells = parseSpellData(getSpells());
    }


    public string getSpells()
    {
        string spells = string.Empty;

        try
        {
            HttpWebRequest request = WebRequest.Create("http://dnd5eapi.co/api/Spells") as HttpWebRequest;

            using (var response = request.GetResponse())
            {
                using (var reader = new StreamReader(response.GetResponseStream()))
                {
                    spells = reader.ReadToEnd();
                }
            }
        }
        catch (Exception e)
        {
            Console.WriteLine(e);
        }
        Console.WriteLine(spells);
        return spells;
    }

    public ObservableCollection<Spell> parseSpellData(string listOfSpells)
    {
        ObservableCollection<Spell> parsedSpellData = JsonConvert.DeserializeObject<ObservableCollection<Spell>>(listOfSpells); 

        return parsedSpellData as ObservableCollection<Spell>;
    }        
}

public class School
{
    public string url { get; set; }
    public string name { get; set; }
}

public class Class
{
    public string name { get; set; }
    public string url { get; set; }
}

public class Subclass
{
    public string url { get; set; }
    public string name { get; set; }
}

public class Spell
{
    public string _id { get; set; }
    public int index { get; set; }
    public string name { get; set; }
    public List<string> desc { get; set; }
    public List<string> higher_level { get; set; }
    public string page { get; set; }
    public string range { get; set; }
    public List<string> components { get; set; }
    public string material { get; set; }
    public string ritual { get; set; }
    public string duration { get; set; }
    public string concentration { get; set; }
    public string casting_time { get; set; }
    public int level { get; set; }
    public School school { get; set; }
    public List<Class> classes { get; set; }
    public List<Subclass> subclasses { get; set; }
    public string url { get; set; }
}

PM Vizualization Error PM汽化错误

Cannot deserialize the current JSON object (eg{"name":"value"}) into type 'System.Collections.ObjectModel.ObservableCollection´1[NInterpret.interpretedObject]' because the type requires a JSON array (eg [1,2,3]) to deserialize correctly. 无法将当前JSON对象(例如{“ name”:“ value”})反序列化为类型'System.Collections.ObjectModel.ObservableCollection´1 [NInterpret.interpretedObject]',因为该类型需要JSON数组(例如[1,2, 3])正确反序列化。 To fix this error either change the JSON to a JSON array (eg [1,2,3]) or change the deserialized type so that it is a normal .NET type (eg. not a primitive type like integer, not a collection type likan an array or List) that can be deserialized from a JSON object. 要解决此错误,可以将JSON更改为JSON数组(例如[1,2,3]),也可以更改反序列化类型,使其成为普通的.NET类型(例如,不是整数之类的原始类型,而不是一个集合类型)可以从JSON对象反序列化likan一个数组或List)。

The problem is that your JSON is not an array, it's an object containing an array-valued property. 问题是您的JSON不是数组,它是一个包含数组值属性的对象。 You can see this more clearly if you format the JSON returned by http://dnd5eapi.co/api/Spells using https://jsonformatter.curiousconcept.com/ : 如果您使用https://jsonformatter.curiousconcept.com/格式化http://dnd5eapi.co/api/Spells返回的JSON,则可以更清楚地看到:

{
   "count":305,
   "results":[
      {
         "name":"Acid Arrow",
         "url":"http://www.dnd5eapi.co/api/spells/1"
      },
      {
         "name":"Acid Splash",
         "url":"http://www.dnd5eapi.co/api/spells/2"
      }
      // Additional entries omitted
   ]
}

Thus you need to deserialize to a model that contains a "results" collection, rather than to the collection itself. 因此,您需要反序列化到包含"results"集合的模型,而不是集合本身。 One easy way to do this is to use JsonConvert.DeserializeAnonymousType() to specify the wrapper root object: 一种简单的方法是使用JsonConvert.DeserializeAnonymousType()指定包装程序根对象:

public ObservableCollection<Spell> parseSpellData(string listOfSpells)
{
    var parsedSpellData = JsonConvert.DeserializeAnonymousType(listOfSpells, new { results = (ObservableCollection<Spell>)null });

    return parsedSpellData.results;
}   

Working fiddle #1 . 工作提琴#1

Of course you could specify an explicit type for the root as well -- in fact your MainPageViewModel could be used for this purpose if you add [JsonProperty("results")] to availableSpells : 当然,您也可以为根指定一个显式类型-实际上,如果将[JsonProperty("results")]availableSpellsMainPageViewModel可以用于此目的:

class MainPageViewModel
{
    [JsonProperty("results")]
    public ObservableCollection<Spell> availableSpells { get; set; } = new ObservableCollection<Spell>();

    public MainPageViewModel()
    {
        JsonConvert.PopulateObject(getSpells(), this);
    }

Sample working fiddle #2 . 示例工作提琴#2

Actually, your data model seems to have many properties not present in the JSON, where the returned objects in the returned "results" array contain only "name" and "url" properties. 实际上,您的数据模型似乎具有JSON中不存在的许多属性,其中返回的"results"数组中的返回对象仅包含"name""url"属性。 Are you sure you are using the correct data model for this particular API? 您确定为此特定API使用的数据模型正确吗?

Update 更新资料

It looks like the JSON posted in your question is returned by the specific spell API URLs listed in the returned results, eg http://www.dnd5eapi.co/api/spells/1 , which furthermore corresponds to your Spell type. 您问题中发布的JSON似乎由返回结果中列出的特定拼写API URL返回,例如http://www.dnd5eapi.co/api/spells/1 ,它进一步对应于您的Spell类型。 If you're looking to fetch all that spell data at once, you could introduce the following types 如果您希望一次获取所有拼写数据,则可以引入以下类型

public class NameAndUri
{
    public string url { get; set; }
    public string name { get; set; }
}

public class NameAndUri<T> : NameAndUri
{
    public T Deserialize()
    {
        return JsonExtensions.DeserializeFromUri<T>(url);
    }
}

public static partial class JsonExtensions
{
    public static T DeserializeAnonymousTypeFromUri<T>(string uri, T anonymousTypeObject)
    {
        return DeserializeFromUri<T>(uri);
    }

    public static T DeserializeFromUri<T>(string uri)
    {
        HttpWebRequest request = WebRequest.Create(uri) as HttpWebRequest;
        using (var response = request.GetResponse())
        using (var reader = new StreamReader(response.GetResponseStream()))
        using (var jsonReader = new JsonTextReader(reader))
        {
            return JsonSerializer.CreateDefault().Deserialize<T>(jsonReader);
        }
    }
}

And modify MainPageViewModel as follows: 并如下修改MainPageViewModel

class MainPageViewModel
{
    public const string spellUri = "http://dnd5eapi.co/api/Spells";

    public ObservableCollection<Spell> availableSpells { get; set; } // = new ObservableCollection<Spell>();

    public MainPageViewModel()
    {
        availableSpells = parseSpellData(spellUri);
    }

    static ObservableCollection<Spell> parseSpellData(string spellUri)
    {
        var parsedSpellData = JsonExtensions.DeserializeAnonymousTypeFromUri(spellUri, new { results = (List<NameAndUri<Spell>>)null });            
        var query = parsedSpellData.results.Select(s => s.Deserialize());
        return new ObservableCollection<Spell>(query);
    }   
}

Notes: 笔记:

  • As recommended in Newtonsoft: Performance Tips I am deserializing directly from the response streams rather than loading into an intermediate string . 正如Newtonsoft中推荐的那样:性能提示我直接从响应流中反序列化,而不是加载到中间string

  • You might want to replace the School , Class and Subclass types with NameAndUri<T> for some appropriate T . 您可能想用NameAndUri<T>替换SchoolClassSubclass类型,以获得一些适当的T

  • If the performance of loading all the spells at once is not good enough, consider moving to an async solution . 如果一次加载所有咒语的性能不够好,请考虑使用异步解决方案

Sample fiddle #3 which times out on https://dotnetfiddle.net/ but works locally. 示例小提琴#3https://dotnetfiddle.net/上超时,但在本地工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM