如何使用 System.Text.Json 解析带有注释的 JSON?

How can I parse JSON with comments using System.Text.Json?

我有一些包含注释的 JSON(尽管 JSON spec 中严格不允许注释。)如何使用 System.Text.Json 解析此 JSON ?

我收到的JSON如下:

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

当我尝试将其加载到 JsonDocument 中时:

using var doc = JsonDocument.Parse(jsonString);

我得到以下异常:

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

当我尝试使用 JsonSerializer 反序列化时:

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

我遇到类似的异常:

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)

如何用 System.Text.Json 解析或反序列化此 JSON?

JSON 包含评论可以被 System.Text.Json 解析,但是 默认情况下这样的 JSON 被认为是无效的 ,可能是因为评论不是包含在选项中的 JSON standard. Support for comments nevertheless can be enabled by modifying the JsonCommentHandling 枚举中:

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.

在使用 Utf8JsonReader, set JsonReaderOptions.CommentHandling in one of the Utf8JsonReader constructors 直接阅读时允许跳过或加载评论,例如如下:

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

JsonDocument解析时设置JsonDocumentOptions.CommentHandling = JsonCommentHandling.Skip:

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

使用 JsonSerializer 反序列化时设置 JsonSerializerOptions.ReadCommentHandling = JsonCommentHandling.Skip:

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

请注意,从 .NET Core 3.1 开始,JsonDocumentJsonSerializer 仅支持跳过或禁止评论;他们不支持加载它们。如果您尝试为其中任何一个设置 JsonCommentHandling.Allow,您将得到一个异常:

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

(这意味着写 JsonConverter<T>.Read() method, which simplifies comment processing as compared to Newtonsoft where comments are exposed to ReadJson() 时不需要手动跳过注释,每次读取标记时都必须检查。)

有关更多信息,请参阅 How to serialize and deserialize JSON in .NET : Allow comments and trailing commas

演示 fiddle here.