NewtonSoft json转换器"未终止的字符串,预期的分隔符:&#34 ;; "

时间:2016-09-11 12:28:39

标签: c# json json.net

我正在尝试解析调用rest API时得到的json响应。 我面临的问题是反序列化每次都不起作用,即使我正在做同样的请求。我不知道如何修复它,因为try.catch没有做任何更好的事情。

此外,当我试图解析一个非常大的响应(20多个json对象)时,程序永远不会工作。

我自己搜索了这个问题,但我不知道解决方案..

  

未终止的字符串。预期的分隔符:"。路径'饮料[0] .strMeasure4',第3行,第720位。

是我遇到的错误之一,它永远不会相同。

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

    }
}
}

编辑:

我添加了饮料类:

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

我尝试过:

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

它好了5次,然后我得到了这个错误+我收到的json。 第6次也很好。

http://pastebin.com/c0d29L0S(格式更好,然后是下面的粘贴)

反序列化对象时意外结束。 Path&#39; drink [1] .strIngredient1&#39;,第3行,第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":

我理解为什么它现在出错,JSON无效,但这是我收到的回复。所以我用来获取响应的代码是错误的......对吗?

编辑3:

相同的请求,良好的JSON响应:

http://pastebin.com/e3WNxz0W

现在程序正常运行,但它不存在。

3 个答案:

答案 0 :(得分:4)

我想实际问题是你没有评估HTTP响应头。​​

结果很可能是批量发送的,即转移编码是“分块”的,但是你天真的读者只会获得第一个块并使用它,而不是等待更多。这可能会在请求之间发生变化(例如,在直接传递时分块,在缓存后不分块,反之亦然)。所以最后,不要重新发明轮子,只需使用WebClient

Read up the RFC section 3.6.1:

  

3.6.1分块传输编码

     

分块编码会修改消息正文      将其转换为一系列块,每个块都有自己的大小指示器,      然后是包含entity-header字段的可选预告片。这个      允许动态生成的内容与之一起传输      收件人验证其所需的信息      收到了完整的信息。

当您遇到这样的问题时,请尝试将代码拆分为较小的部分,然后检查这些部分是否会产生预期效果。

在您的情况下,您的HTTP下载显然不完整,因此您无法真正责怪JSON解析器吐出错误(因为它们是有效的)。

答案 1 :(得分:2)

我通过以下单元测试再现了您的例外

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

我从您提到的网站获得了价值(http://www.thecocktaildb.com/api/json/v1/1/lookup.php?i=15679) 似乎JSON无效,并且在更改“granita”的文本后,使用不同的引号一切正常!

我所做的手动字符串修改就像:

response = response.Replace("\"", "\\\"");

答案 2 :(得分:0)

我已经通过一些细微的更改来复制您的代码,并且就我所见,它可以正常工作。请注意使用using语句,这是使用IDisposable对象时的一个好习惯以及对象的构造方式(我已经使用了精彩的json2csharp工具):< / p>

internal class Program
{
    private static void Main(string[] args)
    {
        RootObject root = new RootObject();
        using (WebClient wc = new WebClient())
        {
            var json = wc.DownloadString("http://www.thecocktaildb.com/api/json/v1/1/search.php?s=margarita");
            root = JsonConvert.DeserializeObject<RootObject>(json);
        }

        Console.WriteLine(root.drinks.Count);
        Console.ReadLine();
    }
}

public class Drink
{
    public string idDrink { get; set; }
    public string strDrink { get; set; }
    public string strCategory { get; set; }
    public string strAlcoholic { get; set; }
    public string strGlass { get; set; }
    public string strInstructions { get; set; }
    public object strDrinkThumb { get; set; }
    public string strIngredient1 { get; set; }
    public string strIngredient2 { get; set; }
    public string strIngredient3 { get; set; }
    public string strIngredient4 { get; set; }
    public string strIngredient5 { get; set; }
    public string strIngredient6 { get; set; }
    public string strIngredient7 { get; set; }
    public string strIngredient8 { get; set; }
    public string strIngredient9 { get; set; }
    public string strIngredient10 { get; set; }
    public string strIngredient11 { get; set; }
    public string strIngredient12 { get; set; }
    public string strIngredient13 { get; set; }
    public string strIngredient14 { get; set; }
    public string strIngredient15 { get; set; }
    public string strMeasure1 { get; set; }
    public string strMeasure2 { get; set; }
    public string strMeasure3 { get; set; }
    public string strMeasure4 { get; set; }
    public string strMeasure5 { get; set; }
    public string strMeasure6 { get; set; }
    public string strMeasure7 { get; set; }
    public string strMeasure8 { get; set; }
    public string strMeasure9 { get; set; }
    public string strMeasure10 { get; set; }
    public string strMeasure11 { get; set; }
    public string strMeasure12 { get; set; }
    public string strMeasure13 { get; set; }
    public string strMeasure14 { get; set; }
    public string strMeasure15 { get; set; }
    public object dateModified { get; set; }
}
// used http://json2csharp.com/ to get an object from the json string
public class RootObject
{
    public List<Drink> drinks { get; set; }
}