我正在使用 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 = '\0';
ShiftBufferIfNeeded();
ParseUnquotedProperty();
}
else
{
throw JsonReaderException.Create(this, "Invalid property identifier character: {0}.".FormatWith(CultureInfo.InvariantCulture, _chars[_charPos]));
}
// REMAINDER OMITTED
如您所见,没有选项可以配置读取器以引发非双引号属性的异常。
作为解决方法,current Json.NET license允许复制和修改。因此,您应该能够创建自己的从 JsonTextReader
复制的 公共(public)类 StricterJsonTextReader : JsonReader
,并按如下方式修改 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 版本,自己构建它,然后使用它来代替官方版本。无论哪种方式,请务必从您要使用的版本中 fork 源代码:
作为创建自己的解析器的替代方案,您可以使用 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
。Issue #646: Support "strict mode" for RFC7159 parsing 是 closed by JamesNK 。讨论线程列举了
JsonTextReader
扩展 JSON 标准的各种方式,以及 Newtonsoft 尚未实现严格解析器的一些原因。即使问题已解决,您当然可以添加一条评论,请求严格的解析选项。当然,这似乎是他们应该提供的东西。
关于.net - 如何在 JSON .NET 上对属性名称强制使用引号,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53304218/