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

前端 未结 2 454
忘掉有多难
忘掉有多难 2020-12-11 14:50

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 li

相关标签:
2条回答
  • 2020-12-11 15:09

    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.

    0 讨论(0)
  • 2020-12-11 15:09

    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, @"^.+?\(|\)$", "");
    
    0 讨论(0)
提交回复
热议问题