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 版本,自己构建它,然后使用它来代替官方版本。无论哪种方式,请务必从您要使用的版本中分叉源:
作为备选要创建自己的解析器,您可以使用以下命令预处理 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 尚未实现严格解析器的一些原因。
即使问题已解决,您当然可以添加一条评论,请求严格的解析选项。当然,这似乎是他们应该提供的东西。