如何反序列化JSONP响应(最好使用JsonTextReader而不是字符串)?

18 浏览
0 Comments

如何反序列化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,而不是一个字符串(我更喜欢这样做,以避免创建巨大字符串的性能损耗)。即使我使用了那个问题中的建议,它看起来很危险,因为它使用了全局替换。如果没有办法使用流的话,一个安全解析字符串的答案也可以接受。

0
0 Comments

如何使用JsonTextReader反序列化JSONP响应(最好不用字符串)?

最近在处理一个web服务时,我发现它返回的是JSONP格式的数据,这有点奇怪,因为通常情况下,我们需要在请求中包含"?callback"参数才会返回JSONP格式的数据。不过,既然如此,我们可以使用正则表达式来去除方法调用的部分。代码如下:

var x = WebServiceCall();
x = Regex.Replace(x, @"^.+?\(|\)$", "");

但是,我现在不是直接处理字符串了,而是使用了JsonTextReader。而且,尽管我还没有检查过你的正则表达式是否包含了'parseResponse',但它确实可以处理任何JSONP格式的数据。

请注意,我想要使用JsonSerializer的Deserialize方法将数据反序列化为对象,但该方法不接受字符串参数。

是的,我明白。为什么你不能调用`JsonConvert.DeserializeObject(someString)`呢?这个方法是接受字符串参数的。如果你想直接从响应中获取流,并将其放入JSON读取器中,那是行不通的。你必须先处理一下数据。你可以参考这个链接:newtonsoft.com/json/help/html/DeserializeObject.htm

"Method Deserialize does not take string arguments" - `JsonSerializer.Deserialize`有一个重载方法可以接受一个`TextReader`参数,你可以使用`StringReader`来作为`TextReader`的实现。

通过以上内容,我们可以总结出如何使用JsonTextReader反序列化JSONP响应的方法。首先,我们需要使用正则表达式去除方法调用的部分,然后将剩下的部分作为字符串传递给`JsonConvert.DeserializeObject(someString)`方法进行反序列化操作。如果你想直接从流中读取数据并进行反序列化,你可以先将流转换为字符串,然后再进行反序列化操作。这样,我们就可以成功地将JSONP响应反序列化为对象了。

0
0 Comments

问题的原因是,用户想要从一个流中反序列化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(TextReader reader)方法。这样可以避免通过修剪前缀和后缀文本来创建一个新的字符串,并且即使对于较小的字符串,这样做也可以提高性能和内存使用。

以上是解决问题的方法和说明。

0