error deserializing a Json string into a composite object

▼魔方 西西 提交于 2019-12-13 17:36:45

问题


I'm using Newtonsoft's Json.NET. Their documentation is not very helpful.

What I need is to deserialize a json string into a C# object of a class of my authorship. The json string was never an object of this class, I got it using a WebRequest.

I can't post the json string because It has over 34 thousand characters.

Since the object uses a lot of composition, I tryed to generate all the classes needed myself. When I got a FormatException "Input string was not in a correct format." I thought something must be wrong with my classes. I then found this website: http://json2csharp.com/

It's supposed to generate the classes needed for you, so you can deserialize any json string. Apart from generating 3 different classes for the same type (Image), the website generated the exact same classes I had, with different names here and there (for the classes, never the properties). These are the classes:

public class Image
{
    public string full { get; set; }
    public string sprite { get; set; }
    public string group { get; set; }
    public int x { get; set; }
    public int y { get; set; }
    public int w { get; set; }
    public int h { get; set; }
}

public class Skin
{
    public int id { get; set; }
    public string name { get; set; }
    public int num { get; set; }
}

public class Info
{
    public int attack { get; set; }
    public int defense { get; set; }
    public int magic { get; set; }
    public int difficulty { get; set; }
}

public class Stats
{
    public double armor { get; set; }
    public int armorperlevel { get; set; }
    public int attackdamage { get; set; }
    public double attackdamageperlevel { get; set; }
    public int attackrange { get; set; }
    public double attackspeedoffset { get; set; }
    public double attackspeedperlevel { get; set; }
    public int crit { get; set; }
    public int critperlevel { get; set; }
    public int hp { get; set; }
    public int hpperlevel { get; set; }
    public double hpregen { get; set; }
    public double hpregenperlevel { get; set; }
    public int movespeed { get; set; }
    public int mp { get; set; }
    public int mpperlevel { get; set; }
    public double mpregen { get; set; }
    public double mpregenperlevel { get; set; }
    public int spellblock { get; set; }
    public int spellblockperlevel { get; set; }
}

public class Leveltip
{
    public List<string> label { get; set; }
    public List<string> effect { get; set; }
}

public class Image2
{
    public string full { get; set; }
    public string sprite { get; set; }
    public string group { get; set; }
    public int x { get; set; }
    public int y { get; set; }
    public int w { get; set; }
    public int h { get; set; }
}

public class Var
{
    public string key { get; set; }
    public string link { get; set; }
    public List<double> coeff { get; set; }
}

public class Altimage
{
    public string full { get; set; }
    public string sprite { get; set; }
    public string group { get; set; }
    public int x { get; set; }
    public int y { get; set; }
    public int w { get; set; }
    public int h { get; set; }
}

public class Spell
{
    public string name { get; set; }
    public string description { get; set; }
    public string sanitizedDescription { get; set; }
    public string tooltip { get; set; }
    public string sanitizedTooltip { get; set; }
    public Leveltip leveltip { get; set; }
    public Image2 image { get; set; }
    public string resource { get; set; }
    public int maxrank { get; set; }
    public List<int> cost { get; set; }
    public string costType { get; set; }
    public string costBurn { get; set; }
    public List<int> cooldown { get; set; }
    public string cooldownBurn { get; set; }
    public List<List<int>> effect { get; set; }
    public List<string> effectBurn { get; set; }
    public List<Var> vars { get; set; }
    public object range { get; set; }
    public string rangeBurn { get; set; }
    public string key { get; set; }
    public List<Altimage> altimages { get; set; }
}

public class Image3
{
    public string full { get; set; }
    public string sprite { get; set; }
    public string group { get; set; }
    public int x { get; set; }
    public int y { get; set; }
    public int w { get; set; }
    public int h { get; set; }
}

public class Passive
{
    public string name { get; set; }
    public string description { get; set; }
    public string sanitizedDescription { get; set; }
    public Image3 image { get; set; }
}

public class Item
{
    public int id { get; set; }
    public int count { get; set; }
}

public class Block
{
    public string type { get; set; }
    public List<Item> items { get; set; }
    public bool? recMath { get; set; }
}

public class Recommended
{
    public string champion { get; set; }
    public string title { get; set; }
    public string type { get; set; }
    public string map { get; set; }
    public string mode { get; set; }
    public bool priority { get; set; }
    public List<Block> blocks { get; set; }
}

public class RootObject
{
    public int id { get; set; }
    public string key { get; set; }
    public string name { get; set; }
    public string title { get; set; }
    public Image image { get; set; }
    public List<Skin> skins { get; set; }
    public string lore { get; set; }
    public string blurb { get; set; }
    public List<string> allytips { get; set; }
    public List<string> enemytips { get; set; }
    public List<string> tags { get; set; }
    public string partype { get; set; }
    public Info info { get; set; }
    public Stats stats { get; set; }
    public List<Spell> spells { get; set; }
    public Passive passive { get; set; }
    public List<Recommended> recommended { get; set; }
}

This is the code that generates the exception:

RootObject result = JsonConvert.DeserializeObject<RootObject>(jsonString);

I still get the same FormatException at that line. Before reaching the exception though I save the string to a text file and I am then able to visualize it with this software without any errors: http://jsonviewer.codeplex.com/ I can view it's tree structure and it's raw text structure (indented for readability) and there's nothing wrong with the string. Please, can anyone help? I don't know what else to do.

As suggested, here is the pastebin of the json string (my first time using pastebin, I hope I did everything right. I mistyped the name of the paste by the way. It was supposed to be Annie, not anni. It doesn't matter at all, of course): http://pastebin.com/0BWimJMv

Here's the exception details as asked:

System.FormatException was unhandled
HResult=-2146233033
Message=Input string was not in a correct format.
Source=Newtonsoft.Json
StackTrace:
   em Newtonsoft.Json.Utilities.ConvertUtils.Int32Parse(Char[] chars, Int32 start, Int32 length) na c:\Temp\Release\Working\Newtonsoft.Json\Src\Newtonsoft.Json\Utilities\ConvertUtils.cs:linha 608
   em Newtonsoft.Json.JsonTextReader.ParseNumber() na c:\Temp\Release\Working\Newtonsoft.Json\Src\Newtonsoft.Json\JsonTextReader.cs:linha 1199
   em Newtonsoft.Json.JsonTextReader.ParseValue() na c:\Temp\Release\Working\Newtonsoft.Json\Src\Newtonsoft.Json\JsonTextReader.cs:linha 1009
   em Newtonsoft.Json.JsonTextReader.ReadInternal() na c:\Temp\Release\Working\Newtonsoft.Json\Src\Newtonsoft.Json\JsonTextReader.cs:linha 383
   em Newtonsoft.Json.JsonReader.ReadAsInt32Internal() na c:\Temp\Release\Working\Newtonsoft.Json\Src\Newtonsoft.Json\JsonReader.cs:linha 577
   em Newtonsoft.Json.JsonTextReader.ReadAsInt32() na c:\Temp\Release\Working\Newtonsoft.Json\Src\Newtonsoft.Json\JsonTextReader.cs:linha 339
   em Newtonsoft.Json.Serialization.JsonSerializerInternalReader.ReadForType(JsonReader reader, JsonContract contract, Boolean hasConverter) na c:\Temp\Release\Working\Newtonsoft.Json\Src\Newtonsoft.Json\Serialization\JsonSerializerInternalReader.cs:linha 1646
   em Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateList(IList list, JsonReader reader, JsonArrayContract contract, JsonProperty containerProperty, String id) na c:\Temp\Release\Working\Newtonsoft.Json\Src\Newtonsoft.Json\Serialization\JsonSerializerInternalReader.cs:linha 1276
   em Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateList(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, Object existingValue, String id) na c:\Temp\Release\Working\Newtonsoft.Json\Src\Newtonsoft.Json\Serialization\JsonSerializerInternalReader.cs:linha 644
   em Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue) na c:\Temp\Release\Working\Newtonsoft.Json\Src\Newtonsoft.Json\Serialization\JsonSerializerInternalReader.cs:linha 256
   em Newtonsoft.Json.Serialization.JsonSerializerInternalReader.SetPropertyValue(JsonProperty property, JsonConverter propertyConverter, JsonContainerContract containerContract, JsonProperty containerProperty, JsonReader reader, Object target) na c:\Temp\Release\Working\Newtonsoft.Json\Src\Newtonsoft.Json\Serialization\JsonSerializerInternalReader.cs:linha 763
   em Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(Object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, String id) na c:\Temp\Release\Working\Newtonsoft.Json\Src\Newtonsoft.Json\Serialization\JsonSerializerInternalReader.cs:linha 1774
   em Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue) na c:\Temp\Release\Working\Newtonsoft.Json\Src\Newtonsoft.Json\Serialization\JsonSerializerInternalReader.cs:linha 384
   em Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue) na c:\Temp\Release\Working\Newtonsoft.Json\Src\Newtonsoft.Json\Serialization\JsonSerializerInternalReader.cs:linha 254
   em Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateList(IList list, JsonReader reader, JsonArrayContract contract, JsonProperty containerProperty, String id) na c:\Temp\Release\Working\Newtonsoft.Json\Src\Newtonsoft.Json\Serialization\JsonSerializerInternalReader.cs:linha 1276
   em Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateList(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, Object existingValue, String id) na c:\Temp\Release\Working\Newtonsoft.Json\Src\Newtonsoft.Json\Serialization\JsonSerializerInternalReader.cs:linha 644
   em Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue) na c:\Temp\Release\Working\Newtonsoft.Json\Src\Newtonsoft.Json\Serialization\JsonSerializerInternalReader.cs:linha 256
   em Newtonsoft.Json.Serialization.JsonSerializerInternalReader.SetPropertyValue(JsonProperty property, JsonConverter propertyConverter, JsonContainerContract containerContract, JsonProperty containerProperty, JsonReader reader, Object target) na c:\Temp\Release\Working\Newtonsoft.Json\Src\Newtonsoft.Json\Serialization\JsonSerializerInternalReader.cs:linha 763
   em Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(Object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, String id) na c:\Temp\Release\Working\Newtonsoft.Json\Src\Newtonsoft.Json\Serialization\JsonSerializerInternalReader.cs:linha 1774
   em Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue) na c:\Temp\Release\Working\Newtonsoft.Json\Src\Newtonsoft.Json\Serialization\JsonSerializerInternalReader.cs:linha 384
   em Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue) na c:\Temp\Release\Working\Newtonsoft.Json\Src\Newtonsoft.Json\Serialization\JsonSerializerInternalReader.cs:linha 254
   em Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent) na c:\Temp\Release\Working\Newtonsoft.Json\Src\Newtonsoft.Json\Serialization\JsonSerializerInternalReader.cs:linha 177
   em Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType) na c:\Temp\Release\Working\Newtonsoft.Json\Src\Newtonsoft.Json\JsonSerializer.cs:linha 711
   em Newtonsoft.Json.JsonSerializer.Deserialize(JsonReader reader, Type objectType) na c:\Temp\Release\Working\Newtonsoft.Json\Src\Newtonsoft.Json\JsonSerializer.cs:linha 663
   em Newtonsoft.Json.JsonConvert.DeserializeObject(String value, Type type, JsonSerializerSettings settings) na c:\Temp\Release\Working\Newtonsoft.Json\Src\Newtonsoft.Json\JsonConvert.cs:linha 797
   em Newtonsoft.Json.JsonConvert.DeserializeObject[T](String value, JsonSerializerSettings settings) na c:\Temp\Release\Working\Newtonsoft.Json\Src\Newtonsoft.Json\JsonConvert.cs:linha 757
   em Newtonsoft.Json.JsonConvert.DeserializeObject[T](String value) na c:\Temp\Release\Working\Newtonsoft.Json\Src\Newtonsoft.Json\JsonConvert.cs:linha 694
   em LoLWebRequests.LoLWeb.WebGETChampion(String realm, Int32 id) na c:\Users\Charon\Documents\Visual Studio 2012\Projects\LoLWebAPI\LoLWebRequests\LoLWeb.cs:linha 23
   em ConsoleTestApp.Program.Main(String[] args) na c:\Users\Charon\Documents\Visual Studio 2012\Projects\LoLWebAPI\ConsoleTestApp\Program.cs:linha 14
   em System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
   em System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
   em Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
   em System.Threading.ThreadHelper.ThreadStart_Context(Object state)
   em System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   em System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   em System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   em System.Threading.ThreadHelper.ThreadStart()
InnerException: 

Here's the code I use to get the json:

string uri = https://na.api.pvp.net//api/lol/static-data/br/v1.2/champion/1"?locale=en_US&champData=all&api_key=XXX" //key ommited
Uri serviceUri = new Uri(uri);
WebClient downloader = new WebClient();
string jsonWebResult;

try
{
    Stream responseStream = downloader.OpenRead(serviceUri);

    using (StreamReader sr = new StreamReader(responseStream))
    {
        jsonWebResult = sr.ReadToEnd();
    }
}
catch (WebException webEx)
{
    throw webEx;
}

RootObject result = JsonConvert.DeserializeObject<RootObject>(jsonWebResult);

回答1:


I just tried parsing that with the string from pastebin and the classes used above. I was successfully able to parse it into the result object with no FormatException.

I would strongly suspect that it is a problem with how you are getting the jsonString contents. In particularly I would suspect there is a problem with double quotes inside the strings possibly not escaping properly:

"tooltip" : "Deals {{ e1 }} <span class=\"color99FF99\">(+{{ a1 }})</span> magic...",

The following code worked for me:

string jsonString =
            "{\"id\":1,\"key\":\"Annie\",\"name\":\"Annie\",\"title\":\"the Dark Child\",\"image\":{\"full\":\"Annie.png\",\"sprite\":\"champion0.png\",\"group\":\"champion\",\"x\":288,\"y\":0,\"w\":48,\"h\":48},\"skins\":[{\"id\":1000,\"name\":\"default\",\"num\":0},{\"id\":1001,\"name\":\"Goth Annie\",\"num\":1},{\"id\":1002,\"name\":\"Red Riding Annie\",\"num\":2},{\"id\":1003,\"name\":\"Annie in Wonderland\",\"num\":3},{\"id\":1004,\"name\":\"Prom Queen Annie\",\"num\":4},{\"id\":1005,\"name\":\"Frostfire Annie\",\"num\":5},{\"id\":1006,\"name\":\"Reverse Annie\",\"num\":6},{\"id\":1007,\"name\":\"FrankenTibbers Annie\",\"num\":7},{\"id\":1008,\"name\":\"Panda Annie\",\"num\":8}],\"lore\":\"In the time shortly before the League, there were those within the sinister city-state of Noxus who did not agree with the evils perpetrated by the Noxian High Command. The High Command had just put down a coup attempt from the self-proclaimed Crown Prince Raschallion, and a crack down on any form of dissent against the new government was underway. These political and social outcasts, known as the Gray Order, sought to leave their neighbors in peace as they pursued dark arcane knowledge. The leaders of this outcast society were a married couple: Gregori Hastur, the Gray Warlock, and his wife Amoline, the Shadow Witch. Together they led an exodus of magicians and other intelligentsia from Noxus, resettling their followers beyond the Great Barrier to the northern reaches of the unforgiving Voodoo Lands. Though survival was a challenge at times, the Gray Order's colony managed to thrive in a land where so many others would have failed.<br><br>Years after the exodus, Gregori and Amoline had a child: Annie. Early on, Annie's parents knew there was something special about their daughter. At the age of two, Annie miraculously ensorcelled a shadow bear - a ferocious denizen of the petrified forests outside the colony - turning it into her pet. To this day she keeps her bear ''Tibbers'' by her side, often keeping him spellbound as a stuffed doll to be carried like a child's toy. The combination of Annie's lineage and the dark magic of her birthplace have given this little girl tremendous arcane power. It is this same girl who now finds herself as one of the most sought-after champions within the League of Legends - even by the city-state that would have exiled her parents had they not fled beforehand.<br><br>''Annie may be one of the most powerful champions ever to have fought in a Field of Justice. I shudder to think of her capabilities when she becomes an adult.''<br>-- High Councilor Kiersta Mandrake\",\"blurb\":\"In the time shortly before the League, there were those within the sinister city-state of Noxus who did not agree with the evils perpetrated by the Noxian High Command. The High Command had just put down a coup attempt from the self-proclaimed Crown ...\",\"allytips\":[\"Storing a stun for use with her ultimate can turn the tide of a team fight.\",\"Striking killing blows on minions with Disintegrate enables Annie to farm extremely well early in the game.\",\"Molten Shield is a good spell to cast to work up to Annie's stun, so sometimes it's beneficial to grab at least 1 rank in it early.\"],\"enemytips\":[\"Annie's summoned bear, Tibbers, burns opposing units around himself. Try to keep your distance from him after he's been summoned.\",\"Summoner Smite can be used to help take down Tibbers.\",\"Keep an eye out for a white, swirling power around Annie. It means she's ready to unleash her stun.\"],\"tags\":[\"Mage\"],\"partype\":\"Mana\",\"info\":{\"attack\":2,\"defense\":3,\"magic\":10,\"difficulty\":4},\"stats\":{\"armor\":12.5,\"armorperlevel\":4,\"attackdamage\":48,\"attackdamageperlevel\":2.625,\"attackrange\":625,\"attackspeedoffset\":0.08,\"attackspeedperlevel\":1.36,\"crit\":0,\"critperlevel\":0,\"hp\":384,\"hpperlevel\":76,\"hpregen\":4.5,\"hpregenperlevel\":0.55,\"movespeed\":335,\"mp\":250,\"mpperlevel\":50,\"mpregen\":6.9,\"mpregenperlevel\":0.6,\"spellblock\":30,\"spellblockperlevel\":0},\"spells\":[{\"name\":\"Disintegrate\",\"description\":\"Annie hurls a mana-infused fireball, dealing damage and refunding the mana cost if it destroys the target.\",\"sanitizedDescription\":\"Annie hurls a mana-infused fireball, dealing damage and refunding the mana cost if it destroys the target.\",\"tooltip\":\"Deals {{ e1 }} <span class=\\\"color99FF99\\\">(+{{ a1 }})</span> magic damage. Mana cost and half the cooldown are refunded if Disintegrate kills the target.\",\"sanitizedTooltip\":\"Deals {{ e1 }} (+{{ a1 }}) magic damage. Mana cost and half the cooldown are refunded if Disintegrate kills the target.\",\"leveltip\":{\"label\":[\"Damage\",\"Mana Cost\"],\"effect\":[\"{{ e1 }} -> {{ e1NL }}\",\" {{ cost }} -> {{ costnNL }}\"]},\"image\":{\"full\":\"Disintegrate.png\",\"sprite\":\"spell1.png\",\"group\":\"spell\",\"x\":48,\"y\":0,\"w\":48,\"h\":48},\"resource\":\"{{ cost }} Mana\",\"maxrank\":5,\"cost\":[60,65,70,75,80],\"costType\":\"Mana\",\"costBurn\":\"60/65/70/75/80\",\"cooldown\":[4,4,4,4,4],\"cooldownBurn\":\"4\",\"effect\":[[80,115,150,185,220]],\"effectBurn\":[\"80/115/150/185/220\"],\"vars\":[{\"key\":\"a1\",\"link\":\"spelldamage\",\"coeff\":[0.8]}],\"range\":[625,625,625,625,625],\"rangeBurn\":\"625\",\"key\":\"Disintegrate\"},{\"name\":\"Incinerate\",\"description\":\"Annie casts a blazing cone of fire, dealing damage to all enemies in the area.\",\"sanitizedDescription\":\"Annie casts a blazing cone of fire, dealing damage to all enemies in the area.\",\"tooltip\":\"Casts a cone of fire dealing {{ e1 }} <span class=\\\"color99FF99\\\">(+{{ a1 }})</span> magic damage to all enemies in the area.\",\"sanitizedTooltip\":\"Casts a cone of fire dealing {{ e1 }} (+{{ a1 }}) magic damage to all enemies in the area.\",\"leveltip\":{\"label\":[\"Damage\",\"Mana Cost\"],\"effect\":[\"{{ e1 }} -> {{ e1NL }}\",\" {{ cost }} -> {{ costnNL }}\"]},\"image\":{\"full\":\"Incinerate.png\",\"sprite\":\"spell1.png\",\"group\":\"spell\",\"x\":96,\"y\":0,\"w\":48,\"h\":48},\"resource\":\"{{ cost }} Mana\",\"maxrank\":5,\"cost\":[70,80,90,100,110],\"costType\":\"Mana\",\"costBurn\":\"70/80/90/100/110\",\"cooldown\":[8,8,8,8,8],\"cooldownBurn\":\"8\",\"effect\":[[70,115,160,205,250]],\"effectBurn\":[\"70/115/160/205/250\"],\"vars\":[{\"key\":\"a1\",\"link\":\"spelldamage\",\"coeff\":[0.85]}],\"range\":[625,625,625,625,625],\"rangeBurn\":\"625\",\"key\":\"Incinerate\"},{\"name\":\"Molten Shield\",\"description\":\"Increases Annie's Armor and Magic Resist and damages enemies who hit Annie with basic attacks.\",\"sanitizedDescription\":\"Increases Annie's Armor and Magic Resist and damages enemies who hit Annie with basic attacks.\",\"tooltip\":\"Increases Armor and Magic Resist by {{ e1 }} for {{ e3 }} seconds. Deals {{ e2 }} <span class=\\\"color99FF99\\\">(+{{ a1 }})</span> magic damage to enemies who attack Annie with basic attacks.\",\"sanitizedTooltip\":\"Increases Armor and Magic Resist by {{ e1 }} for {{ e3 }} seconds. Deals {{ e2 }} (+{{ a1 }}) magic damage to enemies who attack Annie with basic attacks.\",\"leveltip\":{\"label\":[\"Damage\",\"Armor Bonus\",\"Magic Resist Bonus\"],\"effect\":[\"{{ e2 }} -> {{ e2NL }}\",\"{{ e1 }} -> {{ e1NL }}\",\"{{ e1 }} -> {{ e1NL }}\"]},\"image\":{\"full\":\"MoltenShield.png\",\"sprite\":\"spell1.png\",\"group\":\"spell\",\"x\":144,\"y\":0,\"w\":48,\"h\":48},\"resource\":\"{{ cost }} Mana\",\"maxrank\":5,\"cost\":[20,20,20,20,20],\"costType\":\"Mana\",\"costBurn\":\"20\",\"cooldown\":[0,0,0,0,0],\"cooldownBurn\":\"0\",\"effect\":[[20,30,40,50,60],[20,30,40,50,60],[5,5,5,5,5]],\"effectBurn\":[\"20/30/40/50/60\",\"20/30/40/50/60\",\"5\"],\"vars\":[{\"key\":\"a1\",\"link\":\"spelldamage\",\"coeff\":[0.2]}],\"range\":\"self\",\"rangeBurn\":\"self\",\"key\":\"MoltenShield\"},{\"name\":\"Summon: Tibbers\",\"description\":\"Annie wills her bear Tibbers to life, dealing damage to units in the area. Tibbers can attack and also burns enemies that stand near him.\",\"sanitizedDescription\":\"Annie wills her bear Tibbers to life, dealing damage to units in the area. Tibbers can attack and also burns enemies that stand near him.\",\"tooltip\":\"Tibbers appears in a burst of flame dealing {{ e1 }} <span class=\\\"color99FF99\\\">(+{{ a1 }})</span> magic damage to enemies in the target area.<br><br>For the next {{ e6 }} seconds, Tibbers chases down enemies and deals {{ e4 }}<span class=\\\"color99FF99\\\"> (+{{ a2 }})</span> magic damage each second to nearby foes.<br><br><span class=\\\"color99FF99\\\">Tibbers can be controlled by holding the alt key and using the right mouse button or by reactivating this ability.</span>\",\"sanitizedTooltip\":\"Tibbers appears in a burst of flame dealing {{ e1 }} (+{{ a1 }}) magic damage to enemies in the target area. For the next {{ e6 }} seconds, Tibbers chases down enemies and deals {{ e4 }} (+{{ a2 }}) magic damage each second to nearby foes. Tibbers can be controlled by holding the alt key and using the right mouse button or by reactivating this ability.\",\"leveltip\":{\"label\":[\"Damage\",\"Tibbers Health\",\"Tibbers Armor and Magic Resist\",\"Tibbers Attack Damage\",\"Cooldown\"],\"effect\":[\"{{ e1 }} -> {{ e1NL }}\",\"{{ e2 }} -> {{ e2NL }}\",\"{{ e5 }} -> {{ e5NL }}\",\"{{ e3 }} -> {{ e3NL }}\",\"{{ cooldown }} -> {{ cooldownnNL }}\"]},\"image\":{\"full\":\"InfernalGuardian.png\",\"sprite\":\"spell1.png\",\"group\":\"spell\",\"x\":192,\"y\":0,\"w\":48,\"h\":48},\"resource\":\"{{ cost }} Mana\",\"maxrank\":3,\"cost\":[100,100,100],\"costType\":\"Mana\",\"costBurn\":\"100\",\"cooldown\":[120,100,80],\"cooldownBurn\":\"120/100/80\",\"effect\":[[175,300,425],[1200,2100,3000],[80,105,130],[35,35,35],[30,50,70],[45,45,45]],\"effectBurn\":[\"175/300/425\",\"1200/2100/3000\",\"80/105/130\",\"35\",\"30/50/70\",\"45\"],\"vars\":[{\"key\":\"a1\",\"link\":\"spelldamage\",\"coeff\":[0.8]},{\"key\":\"a2\",\"link\":\"spelldamage\",\"coeff\":[0.2]}],\"range\":[600,600,600],\"rangeBurn\":\"600\",\"key\":\"InfernalGuardian\",\"altimages\":[{\"full\":\"InfernalGuardian0.png\",\"sprite\":\"spell12.png\",\"group\":\"spell\",\"x\":144,\"y\":96,\"w\":48,\"h\":48}]}],\"passive\":{\"name\":\"Pyromania\",\"description\":\"After casting 4 spells, Annie's next offensive spell will stun the target for a short duration.\",\"sanitizedDescription\":\"After casting 4 spells, Annie's next offensive spell will stun the target for a short duration.\",\"image\":{\"full\":\"Annie_Passive.png\",\"sprite\":\"passive0.png\",\"group\":\"passive\",\"x\":288,\"y\":0,\"w\":48,\"h\":48}},\"recommended\":[{\"champion\":\"Annie\",\"title\":\"annieDM\",\"type\":\"riot\",\"map\":\"8\",\"mode\":\"ODIN\",\"priority\":false,\"blocks\":[{\"type\":\"starting\",\"items\":[{\"id\":1001,\"count\":1},{\"id\":1063,\"count\":1},{\"id\":2003,\"count\":2}]},{\"type\":\"essential\",\"items\":[{\"id\":3090,\"count\":1},{\"id\":3020,\"count\":1},{\"id\":3029,\"count\":1}]},{\"type\":\"offensive\",\"items\":[{\"id\":3135,\"count\":1},{\"id\":3100,\"count\":1},{\"id\":3165,\"count\":1}]},{\"type\":\"defensive\",\"items\":[{\"id\":3116,\"count\":1},{\"id\":3001,\"count\":1},{\"id\":3174,\"count\":1}]},{\"type\":\"Consumables\",\"items\":[{\"id\":2003,\"count\":1},{\"id\":2004,\"count\":1}]}]},{\"champion\":\"Annie\",\"title\":\"AnnieFB\",\"type\":\"riot\",\"map\":\"12\",\"mode\":\"FIRSTBLOOD\",\"priority\":false,\"blocks\":[{\"type\":\"starting\",\"items\":[{\"id\":1076,\"count\":1},{\"id\":2003,\"count\":2},{\"id\":3342,\"count\":1}]},{\"type\":\"essential\",\"items\":[{\"id\":3020,\"count\":1},{\"id\":3027,\"count\":1},{\"id\":3089,\"count\":1}]},{\"type\":\"offensive\",\"items\":[{\"id\":3128,\"count\":1},{\"id\":3135,\"count\":1},{\"id\":3001,\"count\":1}]},{\"type\":\"defensive\",\"items\":[{\"id\":3116,\"count\":1},{\"id\":3152,\"count\":1},{\"id\":3157,\"count\":1}]},{\"type\":\"Consumables\",\"items\":[{\"id\":2003,\"count\":1},{\"id\":2004,\"count\":1},{\"id\":2044,\"count\":1}]}]},{\"champion\":\"Annie\",\"title\":\"AnnieSR\",\"type\":\"riot\",\"map\":\"1\",\"mode\":\"CLASSIC\",\"priority\":false,\"blocks\":[{\"type\":\"starting\",\"items\":[{\"id\":1056,\"count\":1},{\"id\":2003,\"count\":2},{\"id\":3340,\"count\":1}]},{\"type\":\"essential\",\"items\":[{\"id\":3020,\"count\":1},{\"id\":3027,\"count\":1},{\"id\":3089,\"count\":1}]},{\"type\":\"offensive\",\"items\":[{\"id\":3128,\"count\":1},{\"id\":3135,\"count\":1},{\"id\":3001,\"count\":1}]},{\"type\":\"defensive\",\"items\":[{\"id\":3116,\"count\":1},{\"id\":3152,\"count\":1},{\"id\":3157,\"count\":1}]},{\"type\":\"Consumables\",\"items\":[{\"id\":2003,\"count\":1},{\"id\":2004,\"count\":1},{\"id\":2044,\"count\":1}]}]},{\"champion\":\"Annie\",\"title\":\"AnnieTT\",\"type\":\"riot\",\"map\":\"10\",\"mode\":\"CLASSIC\",\"priority\":false,\"blocks\":[{\"type\":\"starting\",\"items\":[{\"id\":1056,\"count\":1},{\"id\":1001,\"count\":1}]},{\"type\":\"essential\",\"items\":[{\"id\":3020,\"count\":1},{\"id\":3027,\"count\":1},{\"id\":3090,\"count\":1}]},{\"type\":\"offensive\",\"items\":[{\"id\":3135,\"count\":1},{\"id\":3116,\"count\":1},{\"id\":3187,\"count\":1}]},{\"type\":\"defensive\",\"items\":[{\"id\":3152,\"count\":1},{\"id\":3001,\"count\":1},{\"id\":3170,\"count\":1}]},{\"type\":\"Consumables\",\"items\":[{\"id\":2003,\"count\":1},{\"id\":2004,\"count\":1}]}]},{\"champion\":\"Annie\",\"title\":\"Beginner\",\"type\":\"riot-beginner\",\"map\":\"1\",\"mode\":\"CLASSIC\",\"priority\":false,\"blocks\":[{\"type\":\"beginner_Starter\",\"items\":[{\"id\":1056,\"count\":1},{\"id\":2003,\"count\":1}]},{\"type\":\"beginner_Advanced\",\"recMath\":true,\"items\":[{\"id\":1028,\"count\":1},{\"id\":1027,\"count\":1},{\"id\":3010,\"count\":1}]},{\"type\":\"beginner_MovementSpeed\",\"recMath\":true,\"items\":[{\"id\":1001,\"count\":1},{\"id\":3020,\"count\":1}]},{\"type\":\"beginner_LegendaryItem\",\"recMath\":true,\"items\":[{\"id\":3010,\"count\":1},{\"id\":1026,\"count\":1},{\"id\":3027,\"count\":1}]},{\"type\":\"beginner_MoreLegendaryItems\",\"items\":[{\"id\":3151,\"count\":1},{\"id\":3174,\"count\":1},{\"id\":3116,\"count\":1},{\"id\":3089,\"count\":1}]}]},{\"champion\":\"Annie\",\"title\":\"annieHA\",\"type\":\"riot\",\"map\":\"12\",\"mode\":\"ARAM\",\"priority\":false,\"blocks\":[{\"type\":\"starting\",\"items\":[{\"id\":3096,\"count\":1},{\"id\":1001,\"count\":1},{\"id\":2003,\"count\":3},{\"id\":2004,\"count\":3}]},{\"type\":\"essential\",\"items\":[{\"id\":3020,\"count\":1},{\"id\":3089,\"count\":1},{\"id\":3027,\"count\":1}]},{\"type\":\"offensive\",\"items\":[{\"id\":3128,\"count\":1},{\"id\":3001,\"count\":1},{\"id\":3135,\"count\":1}]},{\"type\":\"defensive\",\"items\":[{\"id\":3003,\"count\":1},{\"id\":3157,\"count\":1},{\"id\":3116,\"count\":1}]},{\"type\":\"Consumables\",\"items\":[{\"id\":2003,\"count\":1},{\"id\":2004,\"count\":1}]}]}]}";

MyJsonContext.RootObject result = JsonConvert.DeserializeObject<MyJsonContext.RootObject>(jsonString);

On a side note, you replace your code with the simpler, and more friendly method DownloadString:

try
{
    using (var client = new WebClient())
    {
        jsonResult = client.DownloadString(serviceUri);
    }
}



回答2:


As soon as the classes got auto-generated by the website I mentioned, I noticed it wasn't safe to have certain fields typed as int and others as double (specially regarding the Stats class), because what is int now may not be int in some other case. So I changed them all to double, not to fix the problem, but hoping that, when I finally fixed it, the classes would be good in all necessary scenarios.

Well, as I ran out of options, I started to look at the auto generated types for the fields of each class again, and I noticed Spell has a List<int> cooldown field. I noticed the corresponding values in the json string were 4.0, five times. I changed the type of cooldown to List<double> and the deserialization worked.

In short, the deserializer never casts a double into an int, but the auto generator sees a number with a zero as it's decimal digit and it creates an int field for it, thus making the auto generator and the deserializer incompatible.

A whole afternoon to find this out. Thanks a lot for all the help, without it I would've quit and made an ugly dynamic deserialization followed by a field by field initialization.



来源:https://stackoverflow.com/questions/24147989/error-deserializing-a-json-string-into-a-composite-object

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!