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

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);


Solution 1:[1]

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();
       (...)

Solution 2:[2]

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);
}

Solution 3:[3]

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

or

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

So you have an array of values.

Solution 4:[4]

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.

Solution 5:[5]

.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.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 tymtam
Solution 2 XAMT
Solution 3 user218887
Solution 4
Solution 5 haldo