skip to Main Content

Sample Json:

{
  "success": true,
  "status": 200,
  "data": [
    {
      "ProfileID": "1001",
      "Name": "Jane Doe",
      "HomePhone": "555-1212",
      "Address1": "123 Elm St"
    },
    {
      "ProfileID": "1002",
      "Name": "Rick Fox",
      "HomePhone": "555-1213",
      "Address1": "123 Ok St"
    }
  ]
}

My code so far:

using Newtonsoft.Json;

private void popGrid()
{
   var client = new HttpClient();
   client.BaseAddress = new Uri("http://the-api/");
   var responseTask = client.GetAsync("member-list");
   responseTask.Wait();
   var result = responseTask.Result;
   if (result.IsSuccessStatusCode)
   {
      var read_response = responseTask.Result.Content.ReadAsStringAsync();
      read_response.Wait();
      var read_result = read_response.Result;

      dynamic response = JsonConvert.DeserializeObject(read_result);
      var success = response.success;
      var status = response.status;
      var data = response.data;

      // List<Root> myDeserializedClass = JsonConvert.DeserializeObject<List<Root>>(data);

      if ((bool)success)
      {
         GridView1.DataSource = data;
         GridView1.DataBind();
      }
   }

}

public class Root
{
   public string ProfileID { get; set; }
   public string Name { get; set; }
   public string HomePhone { get; set; }
   public string Address1 { get; set; }
}

The Errors:
If I run the code as written, it runs through all the way without issue. However when the page renders I get an ugly error:

    Type 'Newtonsoft.Json.Linq.JValue' in Assembly 'Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed' is not marked as serializable.

Buried in the Stack Trace is one line that gives a clue(to me):

    [ArgumentException: Error serializing value '1001' of type 'Newtonsoft.Json.Linq.JValue.']

So then I the added the (commented) line that uses the Root class.
However, if I un-comment that line and run the code, I get the following error:

    Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: 'The best overloaded method match for 'Newtonsoft.Json.JsonConvert.DeserializeObject<System.Collections.Generic.List<Root>>(string)' has some invalid arguments'

The above error seems to indicate that JsonConvert.DeserializeObject won’t accept the var ‘data’ as an input. Any thoughts would be greatly appreciated.

Based on the accepted answer this is my final working solution:

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

const string theAPI = "http://the-api/";
const string otherAPI = "http://other-api/";

protected void Button2_Click(object sender, EventArgs e)
{
   DataTable dt = GetDataTableFromAPI(theAPI, "member-list");
   if (dt.Rows.Count > 0)
   {
      GridView1.DataSource = dt;
      GridView1.DataBind();
      GridView1.HeaderRow.TableSection = TableRowSection.TableHeader;
   }
   else
   {
      // nothing found
   }
}

public DataTable GetDataTableFromAPI(string api, string endPoint) 
{
   var client = new HttpClient();
   client.BaseAddress = new Uri(api);
   var response = client.GetAsync(endPoint).Result;
   if (response.IsSuccessStatusCode)
   {
      var json = response.Content.ReadAsStringAsync().Result;
      var jsonParsed = JObject.Parse(json);
      var success = jsonParsed["success"];
      var status = jsonParsed["status"];
      if ((bool)success)
      {
         DataTable dt = jsonParsed["data"].ToObject<DataTable>();
         return dt;
      }
   }
   return new DataTable();
}

2

Answers


  1. You can simplify the approach. Instead of trying to deserialize only part of the JSON, deserialize the whole thing into an object. Define an object structure which matches it:

    public class Root
    {
        public bool success { get; set; }
        public int status { get; set; }
        public IEnumerable<Profile> data { get; set; }
    }
    
    public class Profile
    {
        public string ProfileID { get; set; }
        public string LastName { get; set; }
        public string FirstName { get; set; }
        public string HomePhone { get; set; }
    }
    

    Then deserialize the response into that:

    var result = JsonConvert.DeserializeObject<Root>(read_result);
    

    Then you can access the collection in that object:

    GridView1.DataSource = result.data;
    
    Login or Signup to reply.
  2. it is better to create async method , but if you can not , you have to fix your code

        var response = client.GetAsync(api).Result;
        if (response.IsSuccessStatusCode)
        {
         var json = response.Content.ReadAsStringAsync().Result;
         var jsonParsed=JObject.Parse(json);
         var success = jsonParsed["success"];
          var status = jsonParsed["status"];
          List<Root> data = jsonParsed["data"].ToObject<List<Root>>();
        
          //or in this case you don't need any custom classes at all
    
           DataTable data = jsonParsed["data"].ToObject<DataTable>();
          
        
          if ((bool)success)
          {
             GridView1.DataSource = data;
             GridView1.DataBind();
          }
    
         } 
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search