System.Text.Json.JsonDocument.Parse array of objects

Viewed 14273

I am trying to parse below json using System.Text.Json.JsonDocument

[
    {
        "Name" : "Test 2",
        "NumberOfComponents" : 1,
        "IsActive" : true,
        "CreatedBy" : "bsharma"
    },
    {
        "Name" : "Test 2",
        "NumberOfComponents" : 1,
        "IsActive" : true,
        "CreatedBy" : "bsharma"
    }
]

The code to parse:

 using var jsonDoc = JsonDocument.Parse(inputStream, _jsonDocumentOptions);

The parsing fails with error:

System.Text.Json.JsonReaderException
  HResult=0x80131500
  Message='[' is an invalid start of a property name. Expected a '"'. LineNumber: 1 | BytePositionInLine: 4.
  Source=System.Text.Json
  StackTrace:
   at System.Text.Json.ThrowHelper.ThrowJsonReaderException(Utf8JsonReader& json, ExceptionResource resource, Byte nextByte, ReadOnlySpan`1 bytes)
   at System.Text.Json.Utf8JsonReader.ReadSingleSegment()
   at System.Text.Json.Utf8JsonReader.Read()
   at System.Text.Json.JsonDocument.Parse(ReadOnlySpan`1 utf8JsonSpan, Utf8JsonReader reader, MetadataDb& database, StackRowStack& stack)
   at System.Text.Json.JsonDocument.Parse(ReadOnlyMemory`1 utf8Json, JsonReaderOptions readerOptions, Byte[] extraRentedBytes)
   at System.Text.Json.JsonDocument.Parse(Stream utf8Json, JsonDocumentOptions options)

The json input is being sent in via an http request. The error message indicates to put the array in a property in form { "values" : [ .. ] }, which solves the problem. Is there a way to get a JsonDocument instance for the original json or the original json is invalid?

EDIT: The json comes from serializing an array:

    var jsonOptions = new JsonSerializerOptions
    {
        WriteIndented = true
    };

    var pocos = new Container[]
    {
        new Container { Name= "Test 2", NumberOfComponents = 2, IsActive = true ,CreatedBy = "bsharma" },
        new Container { Name= "Test 2", NumberOfComponents = 2, IsActive = true ,CreatedBy = "bsharma" }
    };
    var json = JsonSerializer.Serialize(pocos, jsonOptions);
5 Answers

Try the new System.Text.Json APIs from .NET Blog show an example of this.

[
   {
       "date": "2013-01-07T00:00:00Z",
       "temp": 23,
   },
   {
       "date": "2013-01-08T00:00:00Z",
       "temp": 28,
   },
   {
       "date": "2013-01-14T00:00:00Z",
       "temp": 8,
   },
]

...

using (JsonDocument document = JsonDocument.Parse(json, options))
{
   int sumOfAllTemperatures = 0;
   int count = 0;

   foreach (JsonElement element in document.RootElement.EnumerateArray())
   {
       DateTimeOffset date = element.GetProperty("date").GetDateTimeOffset();
       (...)

There is no option in System.Text.Json or Newtonsoft.Json to Deserialize a Json Array without a Name, but you can change the Json String in runtime :

public class SampleList
{
    public List<Sample> Samples { get; set; }
}


public class Sample
{
    public string Name { get; set; }
    public int NumberOfComponents { get; set; }
    public bool IsActive { get; set; }
    public string CreatedBy { get; set; }
}


static void Main(string[] args)
{
    var _jsonDocumentOptions = new JsonSerializerOptions();

    var inputStream = File.ReadAllText("json.txt");

    // Add Json Array name
    inputStream = inputStream.Replace(@"[", "\"Samples\":[");

    var sample = JsonSerializer.Deserialize<SampleList>(inputStream, _jsonDocumentOptions);
}
var values = JsonSerializer.Deserialize<List<Container>>(json);

or

var values = JsonSerializer.Deserialize<Container[]>(json);

So you have an array of values.

Original JSON is invalid.

Check json syntax on https://www.json.org/json-en.html

Of course you may manually trim first/last curly brackets from json string and then parse rest as array, but this does not align with "JsonDocument instance for the original json" in your question.

.NET 6 has added a new namespace System.Text.Json.Nodes which allows access random access to Json values in a similar manner to Newtonsoft.Json JArray and JObject.

You can use JsonNode.Parse() to parse Json from a stream (or string or JsonReader) to a JsonArray.

// parse from stream, string, utf8JsonReader
JsonArray? array = JsonNode.Parse(stream)?.AsArray();

// access values
string name = array[0]["Name"].ToString();
int number = (int) item["NumberOfComponents"];

// or iterate
foreach (var item in array)
{
    string name = item["Name"].ToString();
    int componentCount = (int) item["NumberOfComponents"];
    bool isActive = (bool) item["IsActive"];

    Console.WriteLine($"Name:{name}, #comps:{componentCount}, Active:{isActive}");
}

// serialize
var jsonString = array.ToJsonString();

// deserialize to defined class
List<Item> items = array.Deserialize<List<Item>>();

The addition of JsonObject, JsonArray and JsonNode makes working with Json in System.Text.Json a little easier if you just want to quickly access or modify the Json.

Also see my answer to Equivalent of JObject in System.Text.Json for details on JsonObject.

Related