2016-09-11 2 views
6

Я пытаюсь разобрать ответ json, который я получаю при вызове API для отдыха. Проблема, с которой я столкнулся, заключается в том, что десериализация не работает каждый раз, хотя я делаю тот же запрос. знаю, как это исправить так как try.catch будет ничего лучше не делать.NewtonSoft json converter "unterminated String, ожидаемый разделитель:"; "

Кроме того, когда я пытаюсь разобрать очень большой отклик (20+) JSON объекты программа никогда не работает.

Я гугл проблема сама, но я не знаю решения.

Unterminated string. Ожидаемый разделитель: ". Путь 'напитки [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 «напитки [1] .strIngredient1», строка 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

Теперь программа работает, но это incosistent.

+0

Привет @kevin, я предлагаю вам поставить ваш json (который имеет некоторые проблемы). Трудно найти проблему без деталей json. – Arthas

+0

вы также можете добавить свой класс напитков – silver

+0

Попробуйте захватить данные json, когда вы получите сообщение об ошибке, и покажите его – Steve

ответ

3

Я думаю, актуальной проблемой является вы не оцениваете заголовки ответов HTTP.

Результат, скорее всего, отправляется партиями, то есть кодировка передачи «chunked», но ваш наивный читатель получит только первый кусок и будет использовать его, а не ждать больше. Это может измениться между запросами (например, с помощью прямой передачи, без пометок после кеширования или наоборот). Поэтому, в конце концов, не изобретайте велосипед, просто используйте WebClient.

Read up the RFC section 3.6.1:

3.6.1 поблочного Кодирование

фрагментированное кодирование изменяет тело сообщения для того, чтобы передачи его в виде серии кусков, каждый из которых имеет собственный индикатор размера , , за которым следует ДОПОЛНИТЕЛЬНЫЙ трейлер, содержащий поля заголовка объекта. Этот позволяет передавать динамически производимый контент вместе с информацией , необходимой для того, чтобы получатель подтвердил, что он имеет , получил полное сообщение.


Когда Вы сталкиваетесь проблема, как это, попробуйте разделить ваш код на более мелкие части и проверить, является ли поставить эти части ожидаемых результатов.

В вашем случае ваша загрузка HTTP явно выглядит неполной, поэтому вы не можете обвинять JSON-парсер в том, что он выплевывает ошибки (потому что они действительны).

+0

Проблема: HTTP 1.1 был использован. При использовании HTTP 1.0 проблем нет. Зачем? HTTP 1.1 отправляет в chuncks. Причина для TCPclient, должен был использовать TCP-клиент, чтобы узнать, как с ним работать. –

1

Я воспроизведен ваше исключение с помощью следующего теста блока

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 является недействительным и после изменения текст «гранита», чтобы иметь разные кавычки, все сработало!

ручной струна модификация, которую я сделал это так же, как:

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

Запрос api, который я использовал, работал отлично для меня, я понятия не имею ... тот же код, никаких изменений. –

+0

Я изменил вручную текст «granita» – silver

+0

Это не дает мне никаких исключений, я внес некоторые изменения в главный пост. Проверьте их, пожалуйста. –

0

Я воспроизведен код с некоторыми незначительными изменениями и она отлично работает, насколько я могу видеть.Обратите внимание на использование using отчетности, которая является хорошей практикой при использовании IDisposable объектов и то, как объект constracted (я использовал замечательный json2csharp инструмент для этого):

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

Когда я пытаюсь использовать элемент в переменной для напитков, используя: Console.WriteLine (drinks.drinks.Count); Я все равно получаю сообщение об ошибке каждый раз, потому что получение JSON не выполняется или является неполным. –

+0

Посмотрите на мое редактирование. Я добавил переменную, чтобы удерживать результат, и как только разбор выполняется, я печатаю его на консоль. – Yoav

+0

Я запустил ваш код 3 раза, в 3-й раз он дал ту же ошибку, что и с моим кодом. –

Смежные вопросы