Leon van Wyk
Leon van Wyk

Reputation: 689

Parse/Deserialze JSON in C# where there are named items in the array

I need to deserialize the following JSON:

"response": {
   "records": { 
        "record-1": { "id": "1", "name": "foo" },
        "record-2": { "id": "2", "name": "foo" },
        "record-3": { "id": "3", "name": "foo-bar" }
   }
}

I am using the following C# code to deserialize the above JSON:

HttpWebRequest httpWebRequest 
       = System.Net.WebRequest.Create(requestUrl) as HttpWebRequest;
using (HttpWebResponse httpWebResponse 
                    = httpWebRequest.GetResponse() as HttpWebResponse)
{
   if (httpWebResponse.StatusCode != HttpStatusCode.OK)
        throw new Exception(
              string.Format("Server error (HTTP {0}: {1}).",
                            httpWebResponse.StatusCode, 
                            httpWebResponse.StatusDescription)
        );

   Stream stream = httpWebResponse.GetResponseStream());
   DataContractJsonSerializer dataContractJsonSerializer 
                 = new DataContractJsonSerializer(typeof(MyResponseClass));
   objResponse = dataContractJsonSerializer.ReadObject(stream);
   if (objResponse == null)
        return null;
}

And

[DataContract]
class MyResponseClass
{
    [DataMember]
    public Response response { get; set; }
}
            
[DataContract]
public class Response
{
    [DataMember]
    public Records records { get; set; }
}
        
[DataContract]
public class Records
{
    [DataMember(Name = "record-1")]
    Record record_1 { get; set; }
    [DataMember(Name = "record-2")]
    Record record_2 { get; set; }
    [DataMember(Name = "record-3")]
    Record record_3 { get; set; }
}

[DataContract]
public class Record
{
    [DataMember]
    public string id { get; set; }
    [DataMember]
    public string name { get; set; }
}

Surely there is a better way to get hold of the array of "record" under "records" that makes this scalable instread of defining each record individualy in the code. I know that a JSON reader can be used, but would prefer a simple deserialze routine.

I want to be able to deserialize the JSON into a list of records (e.g. List, how do I achieve this?

Upvotes: 0

Views: 186

Answers (3)

Coder1409
Coder1409

Reputation: 498

Solution is simple your json format

{
  "response": {
     "records": {
         "record-1": { "id": "1", "name": "foo"},
         "record-2": { "id": "2", "name": "foo"},
         "record-3": { "id": "3", "name": "foo-bar"}
     }
  }
}

can be parsed with json.net in a simple and powerfull way with this code

var recordsJson = jsonObject.SelectToken("response")
                     .SelectToken("records")
                     .Children<JProperty>()
                     .Select(p=>p.Value)
                     .ToList();
foreach (var rec in recordsJson)
{
  var record = JsonConvert.DeserializeObject<Record>(rec.ToString());
  Records.Add(record);
}

We get all the records into a jobject list then parse each of them in the simplest way ever and add each record to a list

Upvotes: 0

Leon van Wyk
Leon van Wyk

Reputation: 689

  MyResponse myResponse = null;

  HttpWebRequest httpWebRequest = System.Net.WebRequest.Create(requestUrl) as HttpWebRequest;
  using (HttpWebResponse httpWebResponse = httpWebRequest.GetResponse() as HttpWebResponse)
  {
    if (httpWebResponse.StatusCode != HttpStatusCode.OK)
        throw new Exception(string.Format("Server error (HTTP {0}: {1}).", httpWebResponse.StatusCode, httpWebResponse.StatusDescription));

    Stream stream = httpWebResponse.GetResponseStream());
    using (StreamReader streamReader = new StreamReader(stream))
    {
        myResponse = JsonConvert.DeserializeObject<MyResponse>(streamReader.ReadToEnd());

    }
  }

  return myResponse;



[DataContract]
class MyResponseClass
{
    [DataMember]
    public Response response { get; set; }
}

[DataContract]
public class Response
{
    [DataMember(Name = "records")]
    public IDictionary<string, Record> Records { get; set; }
}

[DataContract]
public class Record
{
    [DataMember]
    public string id { get; set; }
    [DataMember]
    public string name { get; set; }
}

Upvotes: 0

Aleksandr Ivanov
Aleksandr Ivanov

Reputation: 2786

I think in you case it would be better to remove Records class at all and and in Response class change type of Records property to IDictionary<string, Record>. So your class structure might look like that:

[DataContract]
class MyResponseClass
{
    [DataMember(Name = "response")]
    public Response Response { get; set; }
}

[DataContract]
public class Response
{
    [DataMember(Name = "records")]
    public IDictionary<string, Record> Records { get; set; }
}

[DataContract]
public class Record
{
    [DataMember(Name = "id")]
    public string Id { get; set; }

    [DataMember(Name = "name")]
    public string Name { get; set; }
}

You can always think of JSON as IDictionary<string, object> in C#. It makes understanding of JSON much easier.

I also suggest to use Name property of DataMember attribute because you can keep C# property naming according to guidelines.

Upvotes: 1

Related Questions