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

2023-12-13

我正在使用 Json.NET 解析我收到的一些 JSON,并将其发送到我的应用程序上的端点。

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

{
  foo: "bar"
}

JToken.Parse()说它是有效的 JSON。然而,当我使用在线解析器我收到以下错误

字符串应该用双引号引起来。

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


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

内部JToken.Parse()构造一个JsonTextReader解析 JSON 字符串,看起来有以下能力JsonTextReader当前无法禁用解析未加引号的属性名称。

当通过以下方式迭代 JSON 文件时JsonTextReader.Read(), 方法JsonTextReader.ParseProperty()用于解析属性名称:

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

并且,从当前参考源,此方法自动处理双引号、单引号和不带引号的属性:

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

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

    // REMAINDER OMITTED

正如您所看到的,没有选项可以配置读取器以引发非双引号属性的异常。

作为解决方法, the 当前 Json.NET 许可证允许复制和修改。因此你应该能够创建自己的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 版本,自己构建它,然后使用它来代替官方版本。无论哪种方式,请务必从您要使用的版本中分叉源:

Select the correct version

作为备选要创建自己的解析器,您可以使用以下命令预处理 JSONJsonReaderWriterFactory.CreateJsonReader()确保严格遵守 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'}")

相关链接:

  • 禁用对读取(无效 JSON)单引号字符串的支持答案是创建自己的JsonReader.

  • 不带引号的 json 属性名称没有答案。

  • 问题#646:支持 RFC7159 解析的“严格模式”这是由 JamesNK 关闭。讨论线程列举了各种方法JsonTextReader扩展了 JSON 标准,以及 Newtonsoft 尚未实现严格解析器的一些原因。

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在 JSON .NET 上对属性名称强制使用引号 的相关文章

随机推荐