0

I am trying to convert a json response from REST API into a DataTable. The following is my code.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using RestSharp;
using Newtonsoft.Json;
using System.Data;

namespace RestDemo1
{
    class Program
    {
        static void Main(string[] args)
        {
            getEmployeeData();
        }

        public static void getEmployeeData()
        {
            var client = new RestClient("https://crmscf.vidyasystems.com/api/gen/items.php");
            var request = new RestRequest("items");
            var response = client.Execute(request);
            string vJ = "";

            if (response.StatusCode == System.Net.HttpStatusCode.OK)
            {
                string rawResponse = response.Content;
                DataTable tester = (DataTable)JsonConvert.DeserializeObject(rawResponse, (typeof(DataTable)));
            }
        }

        public class Rootobject
        {
            public int success { get; set; }
            public Item[] items { get; set; }

            public class Item
            {
                public string ItemID { get; set; }
                public string ItemName { get; set; }
                public string ItemDesc { get; set; }
                public string MRP { get; set; }
                public string Rate { get; set; }
                public string Unit { get; set; }
                public string Weight { get; set; }
                public string ItemGroup { get; set; }
            }
        }
    }
}

When I try get the data into a table format, I get error:

DataTable tester = (DataTable)JsonConvert.DeserializeObject(rawResponse, (typeof(DataTable)));

Error message- Newtonsoft.Json.JsonSerializationException: 'Unexpected JSON token when reading DataTable. Expected StartArray, got StartObject. Path '', line 1, position 1.'

Stefan Wuebbe
  • 2,109
  • 5
  • 17
  • 28
SDS
  • 13
  • 4
  • 1
    DEBUG! Set a breakpoint after `string rawResponse = response.Content;` Now check the json. – Poul Bak Nov 09 '22 at 12:47
  • I am able to get the response. I am even able to deserialize it using `dynamic json = JsonConvert.DeserializeObject(rawResponse)` – SDS Nov 09 '22 at 13:07
  • @SDS first convert it to array and then deserialize the array `string[] stringArray = new string[]{ someString };` – Vivek Nuna Nov 09 '22 at 13:19
  • Can you please share with us a sample json? – Peter Csala Nov 09 '22 at 14:46
  • The error says it all: `Expected StartArray, got StartObject` - the json is not an array as it should be. – Poul Bak Nov 09 '22 at 16:03
  • I get this kind of raw response from [https://crmscf.vidyasystems.com/api/gen/items.php] -'{"success":1,"items":[{"ItemID":"13","ItemName":"Diamond (50 Kg PP)","ItemDesc":"","MRP":"0","Rate":"0","Unit":"","Weight":"50","ItemGroup":""},{"ItemID":"3","ItemName":"Diamond (59 Kg Jute)","ItemDesc":"","MRP":"0","Rate":"0","Unit":"","Weight":"59","ItemGroup":""},{"ItemID":"2","ItemName":"Diamond (59 Kg PP)","ItemDesc":"","MRP":"0","Rate":"0","Unit":"","Weight":"59","ItemGroup":""},{"ItemID":"12","ItemName":"Diamond (60 Kg PP)","ItemDesc":"","MRP":"0","Rate":"0","Unit":"","Weight":"60","ItemGroup":""} – SDS Nov 09 '22 at 17:12

2 Answers2

0

Sorry for the earlier answer, I think this will solve your issue:

public static async Task Main(string[] args)
{
    using(HttpClient client = new())
    {
        var response = await client.GetStringAsync("https://crmscf.vidyasystems.com/api/gen/items.php");
        JObject jsonObject = JObject.Parse(response);
        var items = JsonConvert.SerializeObject(jsonObject["items"]);
        DataTable tester = (DataTable)JsonConvert.DeserializeObject(items, (typeof(DataTable)));
    }
    Console.WriteLine("Hello, World!");
}
Mustafa Poya
  • 2,615
  • 5
  • 22
  • 36
  • I am able to get a response till `JObject jsonObject = JObject.Parse(response.Content);`. After that I am getting null for iteams and dt – SDS Nov 09 '22 at 20:10
  • Here is the console application created for converting the response to a datatable: https://github.com/Hawre1987/DotNetDataTableFromJson.git – Hawre Salih Nov 10 '22 at 05:43
  • This takes a json response from a file, but I am working with response taken from url of an api. – SDS Nov 10 '22 at 08:14
  • @SDS, I've updated the answer to get the json from your API endpoint instead of a file, chech it please. – Hawre Salih Nov 10 '22 at 10:05
  • change this: JObject jsonObject = JObject.Parse(response.Content); to this: JObject jsonObject = JObject.Parse(response);** – Hawre Salih Nov 10 '22 at 11:53
  • How do i display the the data in gridview? Can u share a code snippet – SDS Nov 10 '22 at 11:58
  • I think this should answer your last question, however I did not test it myself: https://stackoverflow.com/questions/22028006/populate-gridview-from-data-table – Hawre Salih Nov 10 '22 at 12:16
0

Your response is a Rootobject type, but not a DataTable type. Hence, you can't deserialize the response.Content to DataTable type.

What you need to do:

  1. Deserialize response.Content to the Rootobject instance.

  2. Extract the items (a list with List<Rootobject.Item> type) from the Rootobject instance.

  3. Convert the List<Rootobject.Item> to DataTable via the extension method IListExtensions.ToDataTable<T>(this IList<T> list).

string rawResponse = response.Content;
                
var root = JsonConvert.DeserializeObject<Rootobject>(rawResponse);
                
DataTable dt = root.items.ToDataTable<Rootobject.Item>();
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;

public static class IListExtensions
{
    public static DataTable ToDataTable<T>(this IList<T> list)
    {
        PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(typeof(T));
        DataTable dataTable = new DataTable();

        foreach (PropertyDescriptor property in properties)
            dataTable.Columns.Add(property.Name, Nullable.GetUnderlyingType(property.PropertyType) ?? property.PropertyType);

        if (list == null)
            return dataTable;

        foreach (T item in list)
        {
            DataRow row = dataTable.NewRow();
            foreach (PropertyDescriptor property in properties)
                row[property.Name] = property.GetValue(item) ?? DBNull.Value;

            dataTable.Rows.Add(row);
        }

        return dataTable;
    }
}
Yong Shun
  • 35,286
  • 4
  • 24
  • 46
  • It throws an exception in ToDataTable method in line `foreach (T item in list)' ** System.NullReferenceException: 'Object reference not set to an instance of an object.'** – SDS Nov 10 '22 at 07:35
  • Look like the `list` is `null`, check whether it is `null` and prevent it from executing `foreach` loop if it is `null`. Check my latest change for the answer. – Yong Shun Nov 10 '22 at 07:40
  • Its actually returning me an empty list. Not sure why. Do you have any code which takes an json response from a dummy rest api and displays the data in a table format? – SDS Nov 10 '22 at 08:09
  • Checked this [demo](https://dotnetfiddle.net/LgBodf). I used your provided API URL and it works. You need to check whether the API returns the response and is it matched to your model class before converting to DataTable. – Yong Shun Nov 10 '22 at 08:12
  • Is there any replacement for `FiddleHelper.WriteTable(dt);` to display ta data? – SDS Nov 10 '22 at 09:36
  • Hi, you may have a read: [Print Contents Of A DataTable](https://stackoverflow.com/q/15547959/8017690) – Yong Shun Nov 10 '22 at 23:15
  • I am not able to display the table data. I am using a console application. I tried printing the data using foreach loop but the output console keeps closing after displaying for a millisecond. – SDS Nov 13 '22 at 12:31
  • Add `Console.ReadLine()` in the end. This will prevent the program exit until you press any key. – Yong Shun Nov 13 '22 at 13:01