1

i am very new to C# and Visualstudio2017 and have been stuck on this for literally weeks. Searching the net but not finding results relating to this that i can understand properly. What i am trying to do is get json data from https://zkillboard.com/api/stats/characterID/224802743/ then convert it into usable data that i can get and display certain data in certain textboxes. I used https://quicktype.io/ to convert the json into C# array.

MainForm.cs

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using System.Net;
using ZKILLBOARDDATA;



namespace MainProgram
{

    public partial class MainForm : Form
    {
        public MainForm()
        {
            InitializeComponent();
            this.DoubleBuffered = true;
            this.SetStyle(ControlStyles.ResizeRedraw, true);

        }


        public async void Btn_submit_ClickAsync(object sender, EventArgs e)
        {
             var remoteUri = "https://zkillboard.com/api/stats/characterID/224802743/";
             var myWebClient = new WebClient();
             myWebClient.Headers.Add("user-agent", "C# App testing");
             var jsonString = await myWebClient.DownloadStringTaskAsync(remoteUri);
             var data = GettingStarted.FromJson(jsonString);
        }   
    }
}

Zkill.cs

using Newtonsoft.Json;
// To parse this JSON data, add NuGet 'Newtonsoft.Json' then do:
//
//    using ZKILLBOARDDATA;
//
//    var data = GettingStarted.FromJson(jsonString);
//
namespace ZKILLBOARDDATA
{

    public partial class GettingStarted
    {
        [JsonProperty("attackers")]
        public Attacker[] Attackers { get; set; }

        [JsonProperty("killmail_id")]
        public long KillmailId { get; set; }

        [JsonProperty("killmail_time")]
        public string KillmailTime { get; set; }

        [JsonProperty("moon_id")]
        public long? MoonId { get; set; }

        [JsonProperty("solar_system_id")]
        public long SolarSystemId { get; set; }

        [JsonProperty("victim")]
        public Victim Victim { get; set; }

        [JsonProperty("war_id")]
        public long? WarId { get; set; }

        [JsonProperty("zkb")]
        public Zkb Zkb { get; set; }
    }

    public partial class Zkb
    {
        [JsonProperty("awox")]
        public bool Awox { get; set; }

        [JsonProperty("fittedValue")]
        public double FittedValue { get; set; }

        [JsonProperty("hash")]
        public string Hash { get; set; }

        [JsonProperty("locationID")]
        public long LocationID { get; set; }

        [JsonProperty("npc")]
        public bool Npc { get; set; }

        [JsonProperty("points")]
        public long Points { get; set; }

        [JsonProperty("solo")]
        public bool Solo { get; set; }

        [JsonProperty("totalValue")]
        public double TotalValue { get; set; }
    }

    public partial class Victim
    {
        [JsonProperty("alliance_id")]
        public long? AllianceId { get; set; }

        [JsonProperty("character_id")]
        public long? CharacterId { get; set; }

        [JsonProperty("corporation_id")]
        public long CorporationId { get; set; }

        [JsonProperty("damage_taken")]
        public long DamageTaken { get; set; }

        [JsonProperty("items")]
        public Item[] Items { get; set; }

        [JsonProperty("position")]
        public Position Position { get; set; }

        [JsonProperty("ship_type_id")]
        public long ShipTypeId { get; set; }
    }

    public partial class Position
    {
        [JsonProperty("x")]
        public double X { get; set; }

        [JsonProperty("y")]
        public double Y { get; set; }

        [JsonProperty("z")]
        public double Z { get; set; }
    }

    public partial class Item
    {
        [JsonProperty("flag")]
        public long Flag { get; set; }

        [JsonProperty("item_type_id")]
        public long ItemTypeId { get; set; }

        [JsonProperty("items")]
        public Item[] Items { get; set; }

        [JsonProperty("quantity_destroyed")]
        public long? QuantityDestroyed { get; set; }

        [JsonProperty("quantity_dropped")]
        public long? QuantityDropped { get; set; }

        [JsonProperty("singleton")]
        public long Singleton { get; set; }
    }

    public partial class Attacker
    {
        [JsonProperty("alliance_id")]
        public long? AllianceId { get; set; }

        [JsonProperty("character_id")]
        public long? CharacterId { get; set; }

        [JsonProperty("corporation_id")]
        public long? CorporationId { get; set; }

        [JsonProperty("damage_done")]
        public long DamageDone { get; set; }

        [JsonProperty("faction_id")]
        public long? FactionId { get; set; }

        [JsonProperty("final_blow")]
        public bool FinalBlow { get; set; }

        [JsonProperty("security_status")]
        public double SecurityStatus { get; set; }

        [JsonProperty("ship_type_id")]
        public long? ShipTypeId { get; set; }

        [JsonProperty("weapon_type_id")]
        public long? WeaponTypeId { get; set; }
    }

    public partial class GettingStarted
    {
        public static GettingStarted[] FromJson(string json) => JsonConvert.DeserializeObject<GettingStarted[]>(json, Converter.Settings);
    }

    public static class Serialize
    {
        public static string ToJson(this GettingStarted[] self) => JsonConvert.SerializeObject(self, Converter.Settings);
    }

    public class Converter
    {
        public static readonly JsonSerializerSettings Settings = new JsonSerializerSettings
        {
            MetadataPropertyHandling = MetadataPropertyHandling.Ignore,
            DateParseHandling = DateParseHandling.None,
        };
    }
}

Here is the error message i am getting from VS2017.

JsonSerializationException: Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'ZKILLBOARDDATA.GettingStarted[]' because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly.

To fix this error either change the JSON to a JSON array (e.g. [1,2,3]) or change the deserialized type so that it is a normal .NET type (e.g. not a primitive type like integer, not a collection type like an array or List) that can be deserialized from a JSON object. JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object.

Path 'allTimeSum', line 1, position 14.

Sir Rufo
  • 18,395
  • 2
  • 39
  • 73
  • I feel like the error message gives you as good of an answer as you can get, given the information you’ve provided. Your JSON source apparently is not an array. – Sean O'Neil Nov 26 '17 at 06:38
  • What do i need to do to get this working. I have tried using c# inbuilt paste special which doesnt work. Im lost. – DANNY KOVACEV Nov 26 '17 at 06:49
  • The web request returns a JSON **object** (starting with **{**) but your deserialization call expected a JSON **array** (starting with **[**) (the exception message is very clear). Seems you want to cherrypick some data from the returned JSON, but your code has not enough magic powder to complete that task – Sir Rufo Nov 26 '17 at 08:46
  • I just checked the JSON response from the link, and **none** of the GettingStarted properties can be found at any position in that response. – Sir Rufo Nov 26 '17 at 08:57

2 Answers2

0

Try this

     var remoteUri = "https://zkillboard.com/api/stats/characterID/224802743/";
     var myWebClient = new WebClient();
     myWebClient.Headers.Add("user-agent", "C# App testing");
     myWebClient.Headers.Add("content-type", "application/json");

     var jsonString = myWebClient.DownloadStringTaskAsync(remoteUri).Result;

     var obj = JsonConvert.DeserializeObject(jsonString);
     //OR
     var obj = JsonConvert.DeserializeObject<YourModel>(jsonString);

I don't think you need this in your model

public partial class GettingStarted
    {
        public static GettingStarted[] FromJson(string json) => JsonConvert.DeserializeObject<GettingStarted[]>(json, Converter.Settings);
    }

    public static class Serialize
    {
        public static string ToJson(this GettingStarted[] self) => JsonConvert.SerializeObject(self, Converter.Settings);
    }

    public class Converter
    {
        public static readonly JsonSerializerSettings Settings = new JsonSerializerSettings
        {
            MetadataPropertyHandling = MetadataPropertyHandling.Ignore,
            DateParseHandling = DateParseHandling.None,
        };
    }
Hey24sheep
  • 1,172
  • 6
  • 16
  • You can use the data like obj.someProperty and set it in the text area. For ex : textbox1.setText or textbox1.innerHtml = obj.someProeprty; – Hey24sheep Nov 26 '17 at 08:26
  • that code you recommended i remove was generated by https://quicktype.io and so was the classes and jsonobjects. i left it in my code and replaced the code you asked me to try and i am not getting that error anymore, but i am now getting. (this method lacks 'await' operators and will run synchronously.) however how do i go about putting certain data that i received into certain textboxes etc. – DANNY KOVACEV Nov 26 '17 at 08:32
  • it is a windows form application not WPF btw. innerHtml not reconized. neither is setText. i have also tried OutputBox.Text = obj.Zkb.Points; (but its returning error, Cannot implicitly convert type 'long' to 'string') – DANNY KOVACEV Nov 26 '17 at 08:45
  • I didn't know what you were using so I just gave you the normal advice how you could set text in textfield. You are missing the basic things. You could set value like OutputBox.Text = obj.Zkb.Points.toString(). – Hey24sheep Nov 26 '17 at 10:25
  • https://github.com/kovacev/EVE-LOCAL-SCAN i put it on Github so u can try it out. i just cant seem to get it to work properly – DANNY KOVACEV Nov 26 '17 at 12:02
  • @DANNYKOVACEV Use the debugger, put a breakpoint at [this line](https://github.com/kovacev/EVE-LOCAL-SCAN/blob/master/MainProgram/MainForm.cs#L51) and check the property values from *obj*. Every property will have the default value (zero or null). If you want to know why, check my comments below your question – Sir Rufo Nov 26 '17 at 14:32
  • @DANNYKOVACEV Your created model is not okay. When you dynamic deserialize the object you get different object kind of like object within the object. Try this website http://json2csharp.com/# and you will get a new model. In your github you are trying to find obj.Attacker which is not available in the JSON at all. This question is going beyond the scope as well. – Hey24sheep Nov 26 '17 at 15:48
0

I had the same problem; I solved it by using the new default System.Text.Json.JsonSerializer.Deserialize instead of the Newtonsoft's

using System.Text.Json;    
var obj = JsonSerializer.Deserialize<YourMODEL>(jsonStr);

p.s. https://quicktype.io is great (although seems somewhat outdated for C#); I've also tried http://json2csharp.com but my json file is big and it froze up.

Also sometimes (in particularly for deeply nested complex json) quicktype doesn't add the list/array type; e.g. MyObj instead of List<MyObj>. Sometimes it is possible to "fix" it by picking T[] first and then List from the website's generation menu option Use T[] or List<T>.

Neil
  • 7,482
  • 6
  • 50
  • 56