如何反序列化JSONP响应(最好使用JsonTextReader而不是字符串)?
如何反序列化JSONP响应(最好使用JsonTextReader而不是字符串)?
我正在尝试使用一个声称返回JSON的Web服务,但实际上它总是返回JSONP。我没有看到改变该服务行为的办法。\n我想使用NewtonSoft Json.Net来解析结果。我已经声明了一个类,我们称之为MyType,我想将内部JSON结果反序列化为它。\nJSONP:\n
parseResponse({ "total" : "13,769", "lower" : "1", "upper" : "20"})
\n正如您所看到的,这不是正确的JSON,因为它有一个parseResponse(
前缀和)
后缀。虽然这个示例非常简单,但实际的响应可能非常长,达到100K的数量级。\nMyType:\n
public class MyType { public Decimal total; public int lower; public int upper; }
\n在我将Web服务响应转换为流和JsonTextReader之后,我尝试像这样反序列化:\n
(MyType)serializer.Deserialize(jsonTextReader, typeof(MyType));
\n当然,我得到了一个空结果,因为有这个讨厌的带有圆括号的parseResponse。\n我看了一下这个问题,不幸的是没有帮助。实际上,我正在使用一个JsonTextReader来输入JSON,而不是一个字符串(我更喜欢这样做,以避免创建巨大字符串的性能损耗)。即使我使用了那个问题中的建议,它看起来很危险,因为它使用了全局替换。如果没有办法使用流的话,一个安全解析字符串的答案也可以接受。
如何使用JsonTextReader反序列化JSONP响应(最好不用字符串)?
最近在处理一个web服务时,我发现它返回的是JSONP格式的数据,这有点奇怪,因为通常情况下,我们需要在请求中包含"?callback"参数才会返回JSONP格式的数据。不过,既然如此,我们可以使用正则表达式来去除方法调用的部分。代码如下:
var x = WebServiceCall(); x = Regex.Replace(x, @"^.+?\(|\)$", "");
但是,我现在不是直接处理字符串了,而是使用了JsonTextReader。而且,尽管我还没有检查过你的正则表达式是否包含了'parseResponse',但它确实可以处理任何JSONP格式的数据。
请注意,我想要使用JsonSerializer的Deserialize方法将数据反序列化为对象,但该方法不接受字符串参数。
是的,我明白。为什么你不能调用`JsonConvert.DeserializeObject
"Method Deserialize does not take string arguments" - `JsonSerializer.Deserialize`有一个重载方法可以接受一个`TextReader`参数,你可以使用`StringReader`来作为`TextReader`的实现。
通过以上内容,我们可以总结出如何使用JsonTextReader反序列化JSONP响应的方法。首先,我们需要使用正则表达式去除方法调用的部分,然后将剩下的部分作为字符串传递给`JsonConvert.DeserializeObject
问题的原因是,用户想要从一个流中反序列化JSONP响应,但是JSONP格式包含一些前缀和后缀文本,用户希望忽略这些文本并直接从流中读取和反序列化JSON。
为了解决这个问题,可以使用以下扩展方法从JSONP流中反序列化JSON:
public static class JsonExtensions { public static T DeserializeEmbeddedJsonP(Stream stream) { using (var textReader = new StreamReader(stream)) return DeserializeEmbeddedJsonP (textReader); } public static T DeserializeEmbeddedJsonP (TextReader textReader) { using (var jsonReader = new JsonTextReader(textReader.SkipPast('('))) { var settings = new JsonSerializerSettings { CheckAdditionalContent = false, }; return JsonSerializer.CreateDefault(settings).Deserialize (jsonReader); } } } public static class TextReaderExtensions { public static TTextReader SkipPast (this TTextReader reader, char ch) where TTextReader : TextReader { while (true) { var c = reader.Read(); if (c == -1 || c == ch) return reader; } } }
解决方法的说明:
- 在构建JsonTextReader之前,先构建一个StreamReader对象,并在流中跳过第一个'('字符。这样可以将StreamReader定位到实际JSON的开头。
- 在反序列化之前,设置JsonSerializerSettings.CheckAdditionalContent = false,告诉序列化器忽略JSON内容之后的任何字符。尽管默认值似乎已经是false,但仍然需要明确设置,因为底层字段是可空的。
- 同样的代码可以用于从字符串中反序列化嵌入的JSONP,只需将StringReader传递给DeserializeEmbeddedJsonP
以上是解决问题的方法和说明。