1

I'm trying to get the first object out of a json array in c#. The Array looks something like this:

[
 {
  "name": "Joe",
  "id": 1
 },
 {
  "name": "Melinda"
  "id": 2
 }
]

I didn't find a suitable way to do this so I'm asking here. I'm using System.Text.JSON. I'm currently using this code:

class Program
     {
  public static void Main(String[] args)
      {      
          HttpClient client = new HttpClient();
          string url = "example.com";

          string json = client.GetStringAsync(url).ToString()!;

       

          Sensor sensor = JsonSerializer.Deserialize<Sensor>(json)!;
          Console.WriteLine(sensor.id);
      }
     }
public class Sensor
     {
        public string? id { get; set; }
     }

Now, unsurprisingly, when i run this code, System.Text.Json throws an error, but i cant decipher what exactly caused it (prbl bc im stupid):

 inner exception     System.Text.Json.JsonReaderException: 'S' is an invalid start of a value. LineNumber: 0 | BytePositionInLine: 0.
   at System.Text.Json.ThrowHelper.ThrowJsonReaderException(Utf8JsonReader& json, ExceptionResource resource, Byte nextByte, ReadOnlySpan`1 bytes)
   at System.Text.Json.Utf8JsonReader.ConsumeValue(Byte marker)
   at System.Text.Json.Utf8JsonReader.ReadFirstToken(Byte first)
   at System.Text.Json.Utf8JsonReader.ReadSingleSegment()
   at System.Text.Json.Utf8JsonReader.Read()
   at System.Text.Json.Serialization.JsonConverter`1.ReadCore(Utf8JsonReader& reader, JsonSerializerOptions options, ReadStack& state)

Is there an easy way to do this with System.Text.Json or Newtonsoft.Json? Thx

dbc
  • 104,963
  • 20
  • 228
  • 340
Ole1Tau1
  • 11
  • 2
  • You need to deserialise to some type of collection e.g. `Sensor[]`. – Johnathan Barclay May 17 '22 at 15:39
  • 1
    `'S' is an invalid start of a value. LineNumber: 0` - Maybe also take a look at the actual string you are receiving. – Fildor May 17 '22 at 15:47
  • Is the array potentially _very_ long and you are interested in the first item, only? – Fildor May 17 '22 at 15:51
  • @Fildor yes. i want to get the name and id of the first object (Joe). – Ole1Tau1 May 17 '22 at 15:56
  • Asking because I was thinking of a possibility that avoids parsing the whole array, when all you ever need is the first item. But the effort may only be justified if parsing the whole thing is more expensive = if the array can be _very_ long. – Fildor May 17 '22 at 15:58
  • Yes, the actual array that i get from the actual url differs from the example and i cant specify which sensor i want to be returned but then the json looks smthg like this: [{"name": "Joe", "id": 1}] with the [] at the start and begining. – Ole1Tau1 May 17 '22 at 16:00
  • 1
    I suspect the JSON isn't actually what you expect it to be. Print out the value of `json` before you try to deserialize it - it looks like it starts with 'S' which isn't valid JSON... – Jon Skeet May 17 '22 at 16:25

4 Answers4

1

An approach very close to yours:

using System;
using System.Text.Json;
                    
public class Program
{
    public static readonly string data = @"[{""name"": ""Joe"",""id"": 1},{""name"": ""Melinda"", ""id"": 2 }]";
    
    public static void Main()
    {
// System.Text.Json defaults to case-sensitive property matching,
// so I need to switch this to insesitive, if the model adheres 
// to C# naming convention ( Props start with capital letter)
        JsonSerializerOptions jso = new JsonSerializerOptions(){ PropertyNameCaseInsensitive = true };

        // We are deserializing an Array               vv
        var sensors = JsonSerializer.Deserialize<Sensor[]>(data, jso);

        // I do an output for demonstration purposes.
        // You'd want to check for null and size>0 and then use the first element.
        foreach( var sensor in sensors )
        {
            Console.WriteLine($"{sensor.Id:#0} : {sensor.Name}");
        }
    }
}

public class Sensor
{
    public int Id {get; set;}
    public string Name {get; set;}
}

See in action: https://dotnetfiddle.net/t7Dkh8


Another Idea would be to incrementally parse, which is beneficial if the array is long and you only need the first element.

See Incremental JSON Parsing in C# (Needs NewtonSoft, though)


Another remark that I and Jon Skeet already made in comments:

The errormessage you are getting

'S' is an invalid start of a value. LineNumber: 0 ...

hints towards that the received string might not actually be valid json. So you might want to investigate this, too.

You could set a breakpoint and look into the value using the debugger, just spit it out to a text file or if you have logging, log it.

Fildor
  • 14,510
  • 4
  • 35
  • 67
1

You should deserialize json string as new List() and then you can find first element of the list using FirstOrDefault() method as follow :

class Sensor
{
   public int Id { get; set; }
   public string Name { get; set; }
}

public Sensor GetFirstElementOfJsonArray(String data)
{
   JsonSerializerOptions options = new JsonSerializerOptions(){ 
   PropertyNameCaseInsensitive = true };
    
   List<Sensor> sensorList=JsonConvert.Deserialize<List<Sensor>>(data,options);
   return sensorList.FirstOrDefault();
}

I think , it will the answer of your question

0

There are two issues that I see in your question. The first is that the id field in the json is not a string but an integer. So you either need to change your json so that it looks like this:

[
  {
    "name": "Joe",
    "id": 1,
 ...

or update your Sensor class to look like this:

public class Sensor
{
   public int id { get; set; }
   public string? name { get; set; }
}

Once you do that though the other issue is that your json is not an object, but an array. so your code needs to look more like this:

      HttpClient client = new HttpClient();
      string url = "example.com";

      string json = client.GetStringAsync(url).ToString()!;

      var sensors = JsonSerializer.Deserialize<IEnumerable<Sensor>>(json)!;
      Console.WriteLine(sensors.First().id);

So serialize the json into a collection (IEnumerable), then you can query that collection to get whatever data you need. Also, I don't know if that was just representative data, but in your json example above, there is a comma missing after "Melinda" in the json.

Nick Cipollina
  • 501
  • 3
  • 13
-1

you need to deserialise to a class:

public class Sensor {
    public int Id { get; set; }
    public string Name { get; set; }
}

JsonSerializer.Deserialize<Sensor>(json)
A Houghton
  • 372
  • 5
  • 18
  • Didn't I do that in Sensor sensor = JsonSerializer.Deserialze(json) – Ole1Tau1 May 17 '22 at 15:46
  • Yes, you did, while you should have `var sensors = JsonSerializer.Deserialize(json);`. Also mind that System.Text.Json defaults to case-sensitive property matching. – Fildor May 17 '22 at 15:49