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
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:
Then deserialize the response into that:
Then you can access the collection in that object:
it is better to create async method , but if you can not , you have to fix your code