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

use*_*745 -5 c# json jsonp json.net

我正在尝试使用声称返回JSON的Web服务,但实际上总是返回JSONP.我没有看到改变该服务行为的方法.

我想用NewtonSoft Json.Net来解析结果.我已经声明了一个类,我们将其称为MyType,我想将内部JSON结果反序列化为.

JSONP:

parseResponse({
"total" : "13,769",
"lower" : "1",
"upper" : "20"})
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,这不是正确的JSON,因为它具有parseResponse(前缀和)后缀.虽然这个例子非常简单,但实际响应可能很长,大约为100K.

我的风格:

public class MyType
{
    public Decimal total;
    public int lower;
    public int upper;
}
Run Code Online (Sandbox Code Playgroud)

在我将Web服务响应转换为流和JsonTextReader之后,我尝试反序列化,如下所示:

(MyType)serializer.Deserialize(jsonTextReader, typeof(MyType));
Run Code Online (Sandbox Code Playgroud)

当然,我得到null的结果,因为有圆括号的那个讨厌的parseResponse.

我看过这个问题,遗憾的是没有帮助.我实际上是使用a JsonTextReader来输入JSON而不是字符串(并且更喜欢这样以避免创建巨大字符串的性能).即使我使用该问题的建议,它看起来很危险,因为它使用全局替换.如果没有好的方法来使用流,那么安全解析字符串的答案就可以了.

dbc*_*dbc 19

如果我将您的问题解释如下:

我试图从一个反序列化一些JSON Stream."JSON"实际上是JSONP格式,因此包含一些我想忽略的前缀和后缀文本.如何在仍然直接从流中读取和反序列化而不是将整个流加载到字符串中时跳过前缀和后缀文本?

然后,您可以使用以下扩展方法从JSONP流反序列化JSON:

public static class JsonExtensions
{
    public static T DeserializeEmbeddedJsonP<T>(Stream stream)
    {
        using (var textReader = new StreamReader(stream))
            return DeserializeEmbeddedJsonP<T>(textReader);
    }

    public static T DeserializeEmbeddedJsonP<T>(TextReader textReader)
    {
        using (var jsonReader = new JsonTextReader(textReader.SkipPast('(')))
        {
            var settings = new JsonSerializerSettings
            {
                CheckAdditionalContent = false,
            };
            return JsonSerializer.CreateDefault(settings).Deserialize<T>(jsonReader);
        }
    }
}

public static class TextReaderExtensions
{
    public static TTextReader SkipPast<TTextReader>(this TTextReader reader, char ch) where TTextReader : TextReader
    {
        while (true)
        {
            var c = reader.Read();
            if (c == -1 || c == ch)
                return reader;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

笔记:

  • 在构造JsonTextReaderI 之前构造a StreamReader并跳过'('流中的第一个字符.这将StreamReader位于实际JSON的开头.

  • 在反JsonSerializerSettings.CheckAdditionalContent = false序列化之前,我设置告诉序列化程序在JSON内容结束后忽略任何字符.奇怪的是,有必要明确地这样做,尽管默认值似乎false已经存在,因为底层字段是可空的.

  • string通过传递给StringReader,可以使用相同的代码从嵌入式JSONP反序列化DeserializeEmbeddedJsonP<T>(TextReader reader);.这样做可以避免通过修剪前缀和后缀文本来创建新字符串,因此即使是较小的字符串也可以提高性能和内存使用率.

样品工作.Net小提琴.


aqu*_*nas 6

看起来它正在返回JSONP。有点奇怪的是,默认情况下,Web服务会执行此操作,而无需包含“?callback”。无论如何,如果只是这样,您可以轻松地使用RegEx除去方法调用:

var x = WebServiceCall();
x = Regex.Replace(x, @"^.+?\(|\)$", "");
Run Code Online (Sandbox Code Playgroud)

  • 是的,我明白了。:)为什么不能调用需要字符串的`JsonConvert.DeserializeObject &lt;MyType&gt;(someString)`?如果您想直接从响应中获取流并将其放入JSON阅读器中,那么它将无法正常工作。您必须先处理它。https://www.newtonsoft.com/json/help/html/DeserializeObject.htm (6认同)
  • @ user6694745-“方法反序列化不接受字符串参数”-`JsonSerializer.Deserialize`具有一个重载,该重载带有`TextReader`,可以是`StringReader`。 (4认同)