19

I have some JSON that includes comments (even though comments aren't strictly allowed in the JSON spec.) How can I parse this JSON using System.Text.Json?

The JSON I have received is as folows:

// A person
{
    "Id" : 1 /* Person's ID */,
    "Name" : "Foo" // Person's name
}

When I attempt to load it into a JsonDocument like so:

using var doc = JsonDocument.Parse(jsonString);

I get the following exception:

System.Text.Json.JsonReaderException: '/' 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)```

And when I attempt to deserialize with JsonSerializer:

var person = JsonSerializer.Deserialize<Person>(jsonString);

I get a similar exception:

System.Text.Json.JsonException: '/' is an invalid start of a value. Path: $ | LineNumber: 0 | BytePositionInLine: 0.
 ---> System.Text.Json.JsonReaderException: '/' 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)

How can I parse or deserialize this JSON with System.Text.Json?

dbc
  • 104,963
  • 20
  • 228
  • 340
  • Technically, it's not legal JSON, as the official JSON syntax doesn't support comments. Nevertheless, most JSON parsers have support for at least ignoring the comments. – Lasse V. Karlsen Dec 22 '19 at 23:00
  • Agreed. Making support for comments be a non-default option is sensible since they're not in the official syntax. – dbc Dec 22 '19 at 23:07

1 Answers1

33

JSON containing comments can be parsed by System.Text.Json, but by default such JSON is considered invalid, likely since comments are not included in the JSON standard. Support for comments nevertheless can be enabled by modifying the JsonCommentHandling enum in options:

Disallow   0   Doesn't allow comments within the JSON input. 
               Comments are treated as invalid JSON if found, and a JsonException is thrown. 
               This is the default value.

Skip       1   Allows comments within the JSON input and ignores them. 
               The Utf8JsonReader behaves as if no comments are present.

Allow      2   Allows comments within the JSON input and treats them as valid tokens. 
               While reading, the caller can access the comment values.

To enable skipping or loading of comments when reading directly with Utf8JsonReader, set JsonReaderOptions.CommentHandling in one of the Utf8JsonReader constructors, e.g. as follows:

static List<string> GetComments(string jsonString)
{
    var options = new JsonReaderOptions 
    { 
        CommentHandling = JsonCommentHandling.Allow 
    };
    var list = new List<string>();
    var reader = new Utf8JsonReader(new ReadOnlySpan<byte>(Encoding.UTF8.GetBytes(jsonString)), options);
    while (reader.Read())
        if (reader.TokenType == JsonTokenType.Comment)
            list.Add(reader.GetComment());
    return list;
}

When parsing with JsonDocument set JsonDocumentOptions.CommentHandling = JsonCommentHandling.Skip:

var options = new JsonDocumentOptions
{
    CommentHandling = JsonCommentHandling.Skip,
};
using var doc = JsonDocument.Parse(jsonString, options);

When deserializing with JsonSerializer set JsonSerializerOptions.ReadCommentHandling = JsonCommentHandling.Skip:

var options = new JsonSerializerOptions
{
    ReadCommentHandling = JsonCommentHandling.Skip
};
var person = JsonSerializer.Deserialize<Person>(jsonString, options);

Note that, as of .NET Core 3.1, JsonDocument and JsonSerializer only support skipping or disallowing of comments; they do not support loading them. If you try to set JsonCommentHandling.Allow for either, you will get an exception:

System.ArgumentOutOfRangeException: Comments cannot be stored in a JsonDocument, only the Skip and Disallow comment handling modes are supported. (Parameter 'value')
System.ArgumentOutOfRangeException: Comments cannot be stored when deserializing objects, only the Skip and Disallow comment handling modes are supported. (Parameter 'value')

(This means that one does not need to manually skip comments when writing a JsonConverter<T>.Read() method, which simplifies comment processing as compared to Newtonsoft where comments are exposed to ReadJson() and must be checked for every time a token is read.)

For more see How to serialize and deserialize JSON in .NET : Allow comments and trailing commas.

Demo fiddle here.

Community
  • 1
  • 1
dbc
  • 104,963
  • 20
  • 228
  • 340