How to deserialize a JSONP response (preferably with JsonTextReader and not a string)?

拜拜、爱过 提交于 2019-12-17 20:42:54

问题


I am trying to consume a web service that claims to return JSON, but actually always returns JSONP. I don't see a way to change that service's behavior.

I would like to use NewtonSoft Json.Net to parse the result. I have declared a class, let's call it MyType that I want to deserialize the inner JSON result into.

JSONP:

parseResponse({
"total" : "13,769",
"lower" : "1",
"upper" : "20"})

As you can see this is not correct JSON as it has parseResponse( prefix and ) suffix. While this example is very simple, the actual response can be quite long, on the order of 100Ks.

MyType:

public class MyType
{
    public Decimal total;
    public int lower;
    public int upper;
}

After I get my web service response into a stream and JsonTextReader I try to deserialize like this:

(MyType)serializer.Deserialize(jsonTextReader, typeof(MyType));

Of course I get null for a result because there is that pesky parseResponse with round brackets.

I've taken a look at this question which unfortunately does not help. I'm actually using a JsonTextReader to feed in the JSON, rather than a string (and prefer so to avoid the performance hit of creating huge a string). Even if I'd use the suggestion from that question, it looks dangerous as it uses a global replace. If there is no good way to use a stream, an answer with safe parsing of strings would be okay.


回答1:


If I interpret your question as follows:

I am trying to deserialize some JSON from a Stream. The "JSON" is actually in JSONP format and so contains some prefix and postfix text I would like to ignore. How can I skip the prefix and postfix text while still reading and deserializing directly from stream rather than loading the entire stream into a string?

Then you can deserialize your JSON from a JSONP stream using the following extension method:

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;
        }
    }
}

Notes:

  • Prior to constructing the JsonTextReader I construct a StreamReader and skip past the first '(' character in the stream. This positions the StreamReader at the beginning of the actual JSON.

  • Before deserialization I set JsonSerializerSettings.CheckAdditionalContent = false to tell the serializer to ignore any characters after the end of the JSON content. Oddly enough it is necessary to do this explicitly despite the fact that the default value seems to be false already, since the underlying field is nullable.

  • The same code can be used to deserialize embedded JSONP from a string by passing a StringReader to DeserializeEmbeddedJsonP<T>(TextReader reader);. Doing so avoids the need to create a new string by trimming the prefix and postfix text and so may improve performance and memory use even for smaller strings.

Sample working .Net fiddle.




回答2:


It looks like it's returning JSONP. Kind of weird that a webservice would do that by default, without you including "?callback". In any case, if that's just the way it is, you can easily use a RegEx to just strip off the method call:

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


来源:https://stackoverflow.com/questions/48470971/how-to-deserialize-a-jsonp-response-preferably-with-jsontextreader-and-not-a-st

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!