Search code examples
c#jsonapijson-deserializationsteam

How to get all Objects from a big Array by an API (C#)


Newtonsoft.Json.JsonReaderException: "Additional text encountered after finished reading JSON content

Hello, I try to get every Object from a big Array provided by an API (steam-API). I need multiple calls to get all the Objects since they are a "total_count":15228. This is my method to get the first page, which works perfectly fine:

public static Task LoadAllItemsAsync()
        {
            int start=0;
            string responseData = "";
            
                
                using (WebClient w = new WebClient())
                {
                    responseData = responseData + w.DownloadString("https://steamcommunity.com/market/search/render/?search_descriptions=0&sort_column=default&sort_dir=desc&appid=730&norender=1&count=100&start=" + start);
                    
                    Thread.Sleep(3000);
                    w.Dispose();
                }
                start = start + 100;
            

            

            dynamic parsedJson = JsonConvert.DeserializeObject(responseData);
            string jsonData = JsonConvert.SerializeObject(parsedJson, Formatting.Indented);
            System.IO.File.WriteAllText(System.IO.Path.GetFullPath(@"..\..\SteamData\SteamItems.json"), jsonData);

            return Task.CompletedTask;

        }

And to get all of the Objects, I try to loop through all pages, by increasing the start value by 100, and here is where I get an exception when I try to deserialize the responsData string. Code:

public static Task LoadAllItemsAsync()
        {
            int start=0;
            string responseData = "";
            for(int i = 0; i <= 1; i++)
            {
                
                using (WebClient w = new WebClient())
                {
                    responseData = responseData + w.DownloadString("https://steamcommunity.com/market/search/render/?search_descriptions=0&sort_column=default&sort_dir=desc&appid=730&norender=1&count=100&start=" + start);
                    
                    Thread.Sleep(3000);
                    w.Dispose();
                }
                start = start + 100;
            }

            

              dynamic parsedJson = JsonConvert.DeserializeObject(responseData); //Newtonsoft.Json.JsonReaderException: "Additional text encountered after finished reading JSON content
            string jsonData = JsonConvert.SerializeObject(parsedJson, Formatting.Indented);
            System.IO.File.WriteAllText(System.IO.Path.GetFullPath(@"..\..\SteamData\SteamItems.json"), jsonData);

            return Task.CompletedTask;

        }

I have found something on google, but I don't understand it and I don't know how to apply it on my code. I highly appreciate any answers.

Edit:
What I have tried:

public static Task LoadAllItemsAsync()
        {
            int start=0;
            string responseData = "";
            string jsonData = "";
            for (int i = 0; i <= 1; i++)
            {               
                using (WebClient w = new WebClient())
                {
                    responseData = responseData + w.DownloadString("https://steamcommunity.com/market/search/render/?search_descriptions=0&sort_column=default&sort_dir=desc&appid=730&norender=1&count=100&start=" + start);
                    dynamic parsedJson = JsonConvert.DeserializeObject(responseData);
                    jsonData = jsonData + JsonConvert.SerializeObject(parsedJson, Formatting.Indented);
                    
                }
                start = start + 100;
            }
            System.IO.File.WriteAllText(System.IO.Path.GetFullPath(@"..\..\SteamData\SteamItems.json"), jsonData);
            return Task.CompletedTask;
        }

Solution

  • Please check following code. The first step is to extract c# types from your json - I used https://json2csharp.com/ for that. Then you should iterate through requests and deserialize each into your objects. Collect all the objects you need in a separate list, serialize and write to file.

    using Newtonsoft.Json;
    using System.Collections.Generic;
    using System.IO;
    using System.Net.Http;
    using System.Threading;
    
    namespace SteamMarketJson
    {
        public class Searchdata
        {
            public string query { get; set; }
            public bool search_descriptions { get; set; }
            public int total_count { get; set; }
            public int pagesize { get; set; }
            public string prefix { get; set; }
            public string class_prefix { get; set; }
        }
    
        public class AssetDescription
        {
            public int appid { get; set; }
            public string classid { get; set; }
            public string instanceid { get; set; }
            public string background_color { get; set; }
            public string icon_url { get; set; }
            public int tradable { get; set; }
            public string name { get; set; }
            public string name_color { get; set; }
            public string type { get; set; }
            public string market_name { get; set; }
            public string market_hash_name { get; set; }
            public int commodity { get; set; }
        }
    
        public class Result
        {
            public string name { get; set; }
            public string hash_name { get; set; }
            public int sell_listings { get; set; }
            public int sell_price { get; set; }
            public string sell_price_text { get; set; }
            public string app_icon { get; set; }
            public string app_name { get; set; }
            public AssetDescription asset_description { get; set; }
            public string sale_price_text { get; set; }
        }
    
        public class RootObject
        {
            public bool success { get; set; }
            public int start { get; set; }
            public int pagesize { get; set; }
            public int total_count { get; set; }
            public Searchdata searchdata { get; set; }
            public List<Result> results { get; set; }
        }
    
        class Program
        {
            static HttpClient httpClient = new HttpClient();
    
            private const string BASE_URL = "https://steamcommunity.com/market/search/render/?search_descriptions=0&sort_column=default&sort_dir=desc&appid=730&norender=1&count=100&start=";
    
            static void Main(string[] args)
            {
                int start = 0;
    
                List<Result> results = new List<Result>(); // you probably want to store results only
                
                RootObject rootObject = null;
                do
                {
                    var response = httpClient.GetAsync(BASE_URL + start).Result; // use await instead of .Result when used in methods
                    var body = response.Content.ReadAsStringAsync().Result;
                    rootObject = JsonConvert.DeserializeObject<RootObject>(body);
    
                    if (rootObject.results != null)
                    {
                        results.AddRange(rootObject.results);
                    }
                    start += 100;
    
                    Thread.Sleep(3000);
                }
                while (start < rootObject.total_count);
    
    
                // write to file
    
                var jsonResult = JsonConvert.SerializeObject(results);
    
                File.WriteAllText("D:\\file.txt", jsonResult);
    
    
                // read and deserialize it back
    
                var fileContent = File.ReadAllText("D:\\file.txt");
    
                var items = JsonConvert.DeserializeObject<List<Result>>(fileContent);
    
    
            }
        }
    }