Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NewtonSoft json converter " unterminated String, expected delimiter : "; "

Tags:

json

c#

json.net

I am trying to parse a json response that I get when calling a rest API. The problem I am facing is that the deserializing doesn't work every time, even though I am making the same request. I don't know how to fix it since a try.catch is not making anything better.

Also, when I am trying to parse a very big response (20+ json objects) the program never works.

I have googled the problem myself but I don't know the solution..

Unterminated string. Expected delimiter: ". Path 'drinks[0].strMeasure4', line 3, position 720.

is one of the errors I am getting, it is never the same.

using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using ConsoleApplication1;

namespace TCPclient
{
class Program
{
    static void Main(string[] args)
    {

        TcpClient client = new TcpClient();

        client.Connect("www.thecocktaildb.com", 80); // geen http
        string request = getRequestCoctail("margarita");


        NetworkStream stream = client.GetStream();


        byte[] buffer = Encoding.Default.GetBytes(request);

        stream.Write(buffer, 0, buffer.Length);
        StringBuilder message = new StringBuilder();
        int numberOfBytesRead = 0;
        byte[] receiveBuffer = new byte[1024];

        do
        {
            numberOfBytesRead = stream.Read(receiveBuffer, 0, receiveBuffer.Length);

            message.AppendFormat("{0}", Encoding.ASCII.GetString(receiveBuffer, 0, numberOfBytesRead));

        } while (stream.DataAvailable);


        string response = message.ToString();

        //Console.WriteLine("Response: \n" + response);
        response = response.Substring(response.IndexOf("\r\n\r\n"));
        try
        {
            dynamic jsonData = JsonConvert.DeserializeObject(response);
            List<Drink> drankjes = new List<Drink>();

            for (int i = 0; i < jsonData.drinks.Count; i++)
            {

                try
                {
                    string id = jsonData.drinks[i].idDrink;
                    string drink = jsonData.drinks[i].strDrink;
                    string category = jsonData.drinks[i].strCategory;
                    string instructions = jsonData.drinks[i].strInstructions;
                    string glass = jsonData.drinks[i].strGlass;
                    Console.WriteLine(glass);
                    var d = new Drink(id, drink, category, instructions);

                    drankjes.Add(d);
                }
                catch (Exception)
                {
                    Console.WriteLine("error");
                }

            }
        }
        catch (Exception e)
        {
            Console.WriteLine(e.Message);
        }


        //Console.WriteLine(jsonData.drinks.Count);


        //Console.WriteLine(jsonData.drinks.Count); get ammount of drinks.
        Console.ReadKey();

    }
    //www.thecocktaildb.com/api/json/v1/1/lookup.php?i=15679
    private static string getRequestCoctail(string coctail)
    {

        ///api/json/v1/1/search.php?s=margarita
        return $"GET /api/json/v1/1/search.php?s=godfather HTTP/1.1\r\n"
                 + "Host: www.thecocktaildb.com\r\n\r\n";
    }

    private static string GetMetaDataCocktail(dynamic jsonData)
    {

        dynamic drink = jsonData.drinks[0];
        return $"DrinkID : {drink.idDrink} \nDrinkName : {drink.strDrink} \nInstructions : {drink.strInstructions}";
    }

    private static Drink GenerateNewDrink(dynamic jsonData)
    {
        Console.WriteLine(jsonData.idDrink, jsonData.strDrink, jsonData.strCategory, jsonData.strInstructions);
        return new Drink(jsonData.idDrink, jsonData.strDrink, jsonData.strCategory, "", jsonData.strInstructions);

    }
}
}

edit :

I added the drink class :

class Drink
{
    public readonly string drinkId;
    public readonly string strDrink;
    public readonly string strCategory;
    public readonly string strInstructions;
    public readonly string strGlass;

    public Drink(string drinkId, string strDrink, string strCategory, string strInstructions)
    {
        this.drinkId = drinkId;
        this.strDrink = strDrink;
        this.strCategory = strCategory;
        this.strInstructions = strInstructions;
    }

    public Drink(string drinkId, string strDrink, string strCategory, string strGlass, string strInstructions)
    {
        this.drinkId = drinkId;
        this.strDrink = strDrink;
        this.strCategory = strCategory;
        this.strGlass = strGlass;
        this.strInstructions = strInstructions;
    }
}
}

I tried it with :

http://www.thecocktaildb.com/api/json/v1/1/search.php?s=godfather

it went good for 5 times, then i got this error + the json i recieved. the 6th time was fine aswell.

http://pastebin.com/c0d29L0S (Better format then the paste below)

Unexpected end when deserializing object. Path 'drinks[1].strIngredient1', line 3, position 1243.

{"drinks":[
{"idDrink":"11423",
"strDrink":"Godfather",
"strCategory":"Ordinary Drink",
"strAlcoholic":"Alcoholic",
"strGlass":"Old-fashioned glass",
"strInstructions":"Pour ingredients into an old-fashioned glass over ice and serve. (Bourbon may be substituted for scotch, if preferred.)",
"strDrinkThumb":null,
"strIngredient1":"Scotch",
"strIngredient2":"Amaretto",
"strIngredient3":"",
"strIngredient4":"",
"strIngredient5":"",
"strIngredient6":"",
"strIngredient7":"",
"strIngredient8":"",
"strIngredient9":"",
"strIngredient10":"",
"strIngredient11":"",
"strIngredient12":"",
"strIngredient13":"",
"strIngredient14":"",
"strIngredient15":"",
"strMeasure1":"1 1\/2 oz ",
"strMeasure2":"3\/4 oz ",
"strMeasure3":" ",
"strMeasure4":" ",
"strMeasure5":" ",
"strMeasure6":" ",
"strMeasure7":" ",
"strMeasure8":"",
"strMeasure9":"",
"strMeasure10":"",
"strMeasure11":"",
"strMeasure12":"",
"strMeasure13":"",
"strMeasure14":"",
"strMeasure15":"",
"dateModified":null
},
{"idDrink":"11538",
"strDrink":"J. R.'s Godfather",
"strCategory":"Ordinary Drink",
"strAlcoholic":"Alcoholic",
"strGlass":"Old-fashioned glass",
"strInstructions":"In an old-fashioned glass almost filled with ice cubes, combine both of the ingredients. Stir to mix the flavors.",
"strDrinkThumb":null,
"strIngredient1":

I understand why it goes wrong right now, the JSON is invalid ofcourse, but this is the response I recieved. So the code I am using to get the response is wrong.. right?

edit 3:

same request, good JSON response :

http://pastebin.com/e3WNxz0W

Now the program works, but it is incosistent.

like image 266
Kevin Van Den Broek Avatar asked Sep 11 '16 12:09

Kevin Van Den Broek


2 Answers

I've reproduced your exception with the following unit test

using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using NUnit.Framework;

//using ConsoleApplication1;

namespace TCPclient
{
    [TestFixture]

    public class Program
    {
        [Test]
        public void Main1()
        {

            string response = GetCoctailString();
            try
            {
                dynamic jsonData = JsonConvert.DeserializeObject(response);
                List<Drink> drankjes = new List<Drink>();

                for (int i = 0; i < jsonData.drinks.Count; i++)
                {

                    try
                    {
                        string id = jsonData.drinks[i].idDrink;
                        string drink = jsonData.drinks[i].strDrink;
                        string category = jsonData.drinks[i].strCategory;
                        string instructions = jsonData.drinks[i].strInstructions;
                        string glass = jsonData.drinks[i].strGlass;
                        Console.WriteLine(glass);
                        var d = new Drink(id, drink, category, instructions);

                        drankjes.Add(d);
                    }
                    catch (Exception)
                    {
                        Console.WriteLine("error");
                    }
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }
            Console.ReadKey();
        }
        private static string GetCoctailString()
        {
            return "{ 'drinks':[{'idDrink':'15679','strDrink':'Midori Margarita','strCategory':'Ordinary Drink','strAlcoholic':'Alcoholic','strGlass':'Cocktail glass','strInstructions':'Moisten rim of cocktail glass with lime juice and dip in salt. Shake ingredients together, and pour into glass filled with crushed ice. Option: Mix above ingredients with one cup of ice in blender for a smooth, \"granita\" type drink.','strDrinkThumb':null,'strIngredient1':'Tequila','strIngredient2':'Triple sec','strIngredient3':'Lime juice','strIngredient4':'Midori melon liqueur','strIngredient5':'Salt','strIngredient6':'','strIngredient7':'','strIngredient8':'','strIngredient9':'','strIngredient10':'','strIngredient11':'','strIngredient12':'','strIngredient13':'','strIngredient14':'','strIngredient15':'','strMeasure1':'1 1/2 oz ','strMeasure2':'1/2 oz ','strMeasure3':'1 oz fresh ','strMeasure4':'1/2 oz ','strMeasure5':'\n','strMeasure6':'\n','strMeasure7':'\n','strMeasure8':'\n','strMeasure9':'\n','strMeasure10':'\n','strMeasure11':'','strMeasure12':'','strMeasure13':'','strMeasure14':'','strMeasure15':'','dateModified':null}]}";
        }
    }
    internal class Drink
    {
        public Drink(string idDrink, string strDrink, string strCategory, string strInstructions){}
        public string idDrink { get; set; }
        public string strDrink { get; set; }
        public string strCategory { get; set; }
        public string empty { get; set; }
        public string strInstructions { get; set; }
    }
}

I've got the value from the site that you've mentioned (http://www.thecocktaildb.com/api/json/v1/1/lookup.php?i=15679) it seems that the JSON is invalid and after changing the text of \"granita\" to have different quotation marks everything worked!

the manual string modification that I've made is just like:

response = response.Replace("\"", "\\\"");
like image 99
silver Avatar answered Nov 19 '22 06:11

silver


I guess the actual problem is you're not evaluating the HTTP response headers.

The result is most likely sent in batches, i.e. the transfer encoding is "chunked", but your naive reader will only get the very first chunk and use that, rather than waiting for more. This might change between requests (e.g. chunked on direct delivery, non-chunked once cached or vice-versa). So in the end, don't reinvent the wheel, just use WebClient.

Read up the RFC section 3.6.1:

3.6.1 Chunked Transfer Coding

The chunked encoding modifies the body of a message in order to transfer it as a series of chunks, each with its own size indicator, followed by an OPTIONAL trailer containing entity-header fields. This allows dynamically produced content to be transferred along with the information necessary for the recipient to verify that it has received the full message.


When you're encountering an issue like this, try to split your code into smaller parts and check to see whether these parts deliver the expected results.

In your case, your HTTP download clearly appears to be incomplete, so you can't really blame the JSON parser for spitting out errors (because they're valid).

like image 6
Mario Avatar answered Nov 19 '22 05:11

Mario