Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Json failing to parse

I have the following JSON string coming back from an API

{"success":true,"data":[
{"id":6,"order_nr":1,"name":"Capture Details","active_flag":true,"deal_probability":100,"pipeline_id":2,"rotten_flag":false,"rotten_days":null,"add_time":"2022-02-09 12:22:26","update_time":"2022-03-14 12:42:16","pipeline_name":"Stove Sales","pipeline_deal_probability":true},
{"id":19,"order_nr":2,"name":"Survey","active_flag":true,"deal_probability":100,"pipeline_id":2,"rotten_flag":false,"rotten_days":null,"add_time":"2022-02-15 13:45:03","update_time":"2022-03-14 12:42:16","pipeline_name":"Stove Sales","pipeline_deal_probability":true},
{"id":9,"order_nr":3,"name":"Quote","active_flag":true,"deal_probability":100,"pipeline_id":2,"rotten_flag":false,"rotten_days":null,"add_time":"2022-02-09 12:22:26","update_time":"2022-03-14 12:42:16","pipeline_name":"Stove Sales","pipeline_deal_probability":true},
{"id":10,"order_nr":4,"name":"Deposit Paid","active_flag":true,"deal_probability":100,"pipeline_id":2,"rotten_flag":false,"rotten_days":null,"add_time":"2022-02-09 12:22:26","update_time":"2022-03-14 12:42:16","pipeline_name":"Stove Sales","pipeline_deal_probability":true},
{"id":11,"order_nr":5,"name":"Order Stove","active_flag":true,"deal_probability":100,"pipeline_id":2,"rotten_flag":false,"rotten_days":null,"add_time":"2022-02-09 12:22:26","update_time":"2022-03-14 12:42:16","pipeline_name":"Stove Sales","pipeline_deal_probability":true},
{"id":12,"order_nr":6,"name":"Contract Agreed","active_flag":true,"deal_probability":100,"pipeline_id":2,"rotten_flag":false,"rotten_days":null,"add_time":"2022-02-09 12:22:26","update_time":"2022-03-14 12:42:16","pipeline_name":"Stove Sales","pipeline_deal_probability":true},
{"id":20,"order_nr":7,"name":"Send Full Ts&Cs for reply","active_flag":true,"deal_probability":100,"pipeline_id":2,"rotten_flag":false,"rotten_days":null,"add_time":"2022-03-14 12:42:16","update_time":"2022-03-14 12:42:16","pipeline_name":"Stove Sales","pipeline_deal_probability":true},
{"id":13,"order_nr":8,"name":"Install Stove","active_flag":true,"deal_probability":100,"pipeline_id":2,"rotten_flag":false,"rotten_days":null,"add_time":"2022-02-09 12:22:26","update_time":"2022-03-14 12:42:16","pipeline_name":"Stove Sales","pipeline_deal_probability":true},
{"id":14,"order_nr":9,"name":"Send Review","active_flag":true,"deal_probability":100,"pipeline_id":2,"rotten_flag":false,"rotten_days":null,"add_time":"2022-02-09 12:22:26","update_time":"2022-03-14 12:42:16","pipeline_name":"Stove Sales","pipeline_deal_probability":true},
{"id":15,"order_nr":1,"name":"Awaiting Sweep","active_flag":true,"deal_probability":100,"pipeline_id":3,"rotten_flag":false,"rotten_days":null,"add_time":"2022-02-12 17:57:35","update_time":"2022-02-12 17:57:35","pipeline_name":"Sweeps","pipeline_deal_probability":true},
{"id":16,"order_nr":2,"name":"Sweep Booked","active_flag":true,"deal_probability":100,"pipeline_id":3,"rotten_flag":false,"rotten_days":null,"add_time":"2022-02-12 17:57:35","update_time":"2022-02-12 17:57:35","pipeline_name":"Sweeps","pipeline_deal_probability":true},
{"id":17,"order_nr":3,"name":"Sweep","active_flag":true,"deal_probability":100,"pipeline_id":3,"rotten_flag":false,"rotten_days":null,"add_time":"2022-02-12 17:57:35","update_time":"2022-02-12 17:57:35","pipeline_name":"Sweeps","pipeline_deal_probability":true},
{"id":18,"order_nr":4,"name":"Send Review","active_flag":true,"deal_probability":100,"pipeline_id":3,"rotten_flag":false,"rotten_days":null,"add_time":"2022-02-12 17:57:35","update_time":"2022-02-12 17:57:35","pipeline_name":"Sweeps","pipeline_deal_probability":true}
]}

Newlines added by me whilst checking the format looked OK. My C# data class looks like this

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace PipedriveClient
{
    internal class PipedriveStage
    {
        // Root myDeserializedClass = JsonConvert.DeserializeObject<Root>(myJsonResponse);
        public class Datum
        {
            public int id { get; set; }
            public int order_nr { get; set; }
            public string name { get; set; }
            public bool active_flag { get; set; }
            public int deal_probability { get; set; }
            public int pipeline_id { get; set; }
            public bool rotten_flag { get; set; }
            public object rotten_days { get; set; }
            public string add_time { get; set; }
            public string update_time { get; set; }
            public string pipeline_name { get; set; }
            public bool pipeline_deal_probability { get; set; }
        }

        public class Root
        {
            public bool success { get; set; }
            public List<Datum> data { get; set; }
        }


    }
}

The code trying to parse it looks like

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

    List<PipedriveStage.Root> stages;

    using (var webClient = new WebClient())
    {
        var response = webClient.DownloadString(url);
        JObject result = JObject.Parse(response);
        var data = result.SelectToken("data");
        stages = JsonConvert.DeserializeObject<List<PipedriveStage.Root>>(data.ToString());
    }

Checking the value of response the response string returned from by webClient is identical, so I’m confident it ought to parse OK. My class I got by using json2csharp.com and the same basic code is working fine for other returns from the same API. I must just be missing something trivially obvious, which I’m hoping will leap out at one of you guys!

>Solution :

Your JSON directly represents a PipedriveStage.Root object. For some reason you’re parsing to JObject, selecting the data token (which is an array, but of Datum), converting that back to a string and then parsing it as if it were a List<Root>.

You can change your code to just:

var root = JsonConvert.DeserializeObject<PipedriveStage.Root>(response);

(Your stages variable isn’t useful here – you don’t logically have multiple roots to deserialize to.)

I would also recommend:

  • Changing the property names to be idiomatic C#, using [JsonProperty] to indicate how they’re represented in JSON. That will make your C# code look more "normal". (json2csharp.com has checkboxes for "Use Pascal Case" and "Add JsonProperty Attributes" that make this trivial.)
  • Using HttpClient instead of WebClient
  • Avoiding nested classes unless you really need to
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading