5

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);
Brij
  • 11,731
  • 22
  • 78
  • 116
  • 2
    Your json string is invalid.How did you get the json?If you just hard encode the json,just change by yourself. – Rena Apr 02 '20 at 05:19
  • Corrected the json string. The json comes from serializing an array `Container[]` – Brij Apr 05 '20 at 21:47
  • Could you share how do you get the json? – Rena Apr 06 '20 at 01:16
  • @Rena, I have added the code which generates json. – Brij Apr 06 '20 at 08:24
  • If i just use `JsonDocument.Parse(json)`,it could not make such issue.What is your `inputStream`? – Rena Apr 06 '20 at 09:02
  • `inputStream` is the stream pointing to json. `JsonDocument.Parse(Stream, JsonDocumentOptions)` method is being used. – Brij Apr 07 '20 at 08:25
  • I see that `JsonDocument.Parse(jsonString)` is working. Looks like something wrong with the stream being read. – Brij Apr 07 '20 at 08:32

5 Answers5

11

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();
       (...)
tymtam
  • 31,798
  • 8
  • 86
  • 126
3

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);
}
XAMT
  • 1,515
  • 2
  • 11
  • 31
3

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

haldo
  • 14,512
  • 5
  • 46
  • 52
2
var values = JsonSerializer.Deserialize<List<Container>>(json);

or

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

So you have an array of values.

user218887
  • 21
  • 1
1

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.

Dmitry
  • 16,110
  • 4
  • 61
  • 73
  • 2
    I don't understand the downvote, since the question at the end is: `Is there a way to get a JsonDocument instance for the original json or the original json is invalid?`, and this answer correctly points out that the json is in fact invalid. – Guilherme Apr 01 '20 at 22:12
  • Most likely the downvote is because per Dmitry's own link, his follow up sentence is incorrect. The grammar at that link indicates that json is an "element", where an "element" is "ws value ws" where ws is whitespace and value is any of "object", "array", "string", "number", or literals "true", "false", "null". I.e. the root of a json document need not be an object. – Joshua W Feb 04 '21 at 02:40