如何在 JSON .NET 上对 属性 名称强制加引号

How to enforce quotes on property names on JSON .NET

我正在使用 Json.NET 解析一些 JSON 我接收到我应用程序中的端点。

我希望以下 JSON 对象无法解析,因为它的 属性 名称没有引号:

{
  foo: "bar"
}

JToken.Parse() 表示有效 JSON。但是,当我使用 online parser 时,出现以下错误

Strings should be wrapped in double quotes.

有没有办法让 JSON .NET 强制执行此规则?

Json.NET 目前没有实现对 JSON 属性 名称的严格解析。

内部JToken.Parse()构造一个JsonTextReader来解析一个JSON字符串,看来JsonTextReader解析不带引号的属性名称的能力目前还不能被禁用。

当通过 JsonTextReader.Read() 遍历 JSON 文件时,方法 JsonTextReader.ParseProperty() 用于解析 属性 名称:

Newtonsoft.Json.JsonTextReader.ParseUnquotedProperty() 
Newtonsoft.Json.JsonTextReader.ParseProperty() 
Newtonsoft.Json.JsonTextReader.ParseObject() 
Newtonsoft.Json.JsonTextReader.Read() 
Newtonsoft.Json.Linq.JContainer.ReadTokenFrom()

并且,从 current reference source 可以看出,此方法自动处理双引号、单引号和未引号的属性:

private bool ParseProperty()
{
    char firstChar = _chars[_charPos];
    char quoteChar;

    if (firstChar == '"' || firstChar == '\'')
    {
        _charPos++;
        quoteChar = firstChar;
        ShiftBufferIfNeeded();
        ReadStringIntoBuffer(quoteChar);
    }
    else if (ValidIdentifierChar(firstChar))
    {
        quoteChar = '[=11=]';
        ShiftBufferIfNeeded();
        ParseUnquotedProperty();
    }
    else
    {
        throw JsonReaderException.Create(this, "Invalid property identifier character: {0}.".FormatWith(CultureInfo.InvariantCulture, _chars[_charPos]));
    }

    // REMAINDER OMITTED

如您所见,没有选项可以配置 reader 以抛出非双引号属性的异常。

作为解决方法current Json.NET license 允许复制和修改。因此,您应该能够创建自己的 public class StricterJsonTextReader : JsonReader,复制自 JsonTextReader,并按如下方式修改 ParseProperty()

private bool ParseProperty()
{
    char firstChar = _chars[_charPos];
    char quoteChar;

    if (firstChar == '"')
    {
        _charPos++;
        quoteChar = firstChar;
        ShiftBufferIfNeeded();
        ReadStringIntoBuffer(quoteChar);
    }
    else
    {
        // JsonReaderException.Create() is an internal static method,
        // so you will need to replace this with some extension method
        throw JsonReaderException.Create(this, "Invalid property identifier character: {0}.".FormatWith(CultureInfo.InvariantCulture, _chars[_charPos]));
    }

然而,这可能不是一项完全容易的工作,因为 JsonTextReader 广泛使用了 Src/Newtonsoft.Json/Utilities 目录中的实用程序。您应该预算几天时间来制作必要实用程序的最小副本。

或者,您可以创建自己的 Json.NET 版本,自己构建,然后使用它代替官方版本。无论哪种方式,请务必从您要使用的版本中分叉源代码:

作为创建自己的解析器的替代方法,您可以使用 JsonReaderWriterFactory.CreateJsonReader() 预处理 JSON 以确保严格遵守 JSON标准:

public static class JsonExtensions
{
    public static JToken StrictParse(string json)
    {
        try
        {
            // Throw an exception if the json string is not in strict compliance with the JSON standard
            // by tokenizing it with the JSON reader used by DataContractJsonSerializer:
            using (var stream = GenerateStreamFromString(json))
            using (var reader = System.Runtime.Serialization.Json.JsonReaderWriterFactory.CreateJsonReader(stream, System.Xml.XmlDictionaryReaderQuotas.Max))
            {
                while (reader.Read())
                {
                }
            }
        }
        catch (Exception ex)
        {
            // Wrap the XmlException in a JsonReaderException
            throw new JsonReaderException("Invalid JSON", ex);
        }
        // Then actually parse with Json.NET
        return JToken.Parse(json);
    }

    static MemoryStream GenerateStreamFromString(string value)
    {
        return new MemoryStream(Encoding.UTF8.GetBytes(value ?? ""));
    }
}

(您需要为您的框架添加对适当的 .Net 程序集的引用。)

性能会更差,因为您将有效地解析您的 JSON 两次,但实现工作是微不足道的。

奇怪的是,我无法使用 JavaScriptSerializer 检查严格的 JSON 合规性,因为它也接受不带引号的 属性 名称!

// The following does not throw an exception:
new System.Web.Script.Serialization.JavaScriptSerializer().DeserializeObject("{foo : 'bar'}")

相关链接:

  • Disable Support for Reading (Invalid JSON) Single Quote Strings 答案是创建您自己的 JsonReader.

  • Unquoted json property name没有答案。

  • Issue #646: Support "strict mode" for RFC7159 parsing which was closed by JamesNK。讨论线程列举了 JsonTextReader 扩展 JSON 标准的各种方式,以及 Newtonsoft 尚未实施严格解析器的一些原因。

    即使问题已关闭,您当然可以添加评论以请求严格的解析选项。当然,这似乎是他们应该提供的东西。