J'essaie d'analyser une réponse json que je reçois lorsque j'appelle une API de repos. Le problème auquel je suis confronté est que la désérialisation ne fonctionne pas à chaque fois, même si je fais la même demande. Je ne sais pas comment le réparer, car try.catch ne fait rien de mieux.
De plus, lorsque j'essaie d'analyser une très grosse réponse (plus de 20 objets json), le programme ne fonctionne jamais.
J'ai moi-même cherché le problème sur Google mais je ne connais pas la solution ..
Chaîne non terminée. Délimiteur attendu: ". Path 'boit [0] .strMeasure4', ligne 3, position 720.
est l'une des erreurs que je reçois, ce n'est jamais la même chose.
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);
}
}
}
modifier :
J'ai ajouté la classe de boisson:
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;
}
}
}
Je l'ai essayé avec:
http://www.thecocktaildb.com/api/json/v1/1/search.php?s=godfather
c’est bien passé 5 fois, puis j’ai eu cette erreur + le json j’ai reçu. La 6ème fois était très bien aussi.
http://Pastebin.com/c0d29L0S (meilleur format que le coller ci-dessous)
Fin inattendue lors de la désérialisation d'un objet. Chemin 'boit [1] .strIngredient1', ligne 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":
Je comprends pourquoi cela se passe mal en ce moment, le JSON n’est bien sûr pas valide, mais c’est la réponse que j’ai reçue. Donc, le code que j'utilise pour obtenir la réponse est faux… non?
éditer 3:
même demande, bonne réponse JSON:
Maintenant, le programme fonctionne, mais il est incohérent.
Je suppose que le problème réel est que vous n'évaluez pas les en-têtes de réponse HTTP.
Le résultat est probablement envoyé par lots, c’est-à-dire que le codage de transfert est "chunké", mais votre lecteur naïf ne recevra que le tout premier chunk et l’utilisera au lieu d’attendre plus. Cela peut changer entre les demandes (par exemple, groupé lors d'une livraison directe, non groupé une fois mis en cache ou inversement). Donc, au final, ne réinventez pas la roue, utilisez simplement WebClient
.
3.6.1 Codage de transfert en bloc
Le codage en bloc modifie le corps d'un message afin de le transférer sous la forme d'une série de morceaux, chacun avec son propre indicateur de taille, Suivi d'une fin facultative contenant des champs d'en-tête d'entité. Ce Permet de transférer le contenu généré de manière dynamique avec les informations Nécessaires pour que le destinataire puisse vérifier qu'il a bien reçu le message complet.
Lorsque vous rencontrez un problème de ce type, essayez de scinder votre code en parties plus petites et vérifiez si ces parties donnent les résultats escomptés.
Dans votre cas, votre téléchargement HTTP apparaît clairement comme étant incomplet. Vous ne pouvez donc pas en vouloir à l’analyseur JSON d’avoir écrit des erreurs (car elles sont valides).
J'ai reproduit votre exception avec le test unitaire suivant
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; }
}
}
J'ai la valeur du site que vous avez mentionné ( http://www.thecocktaildb.com/api/json/v1/1/lookup.php?i=15679 ) il semble que le JSON soit invalide et qu'après avoir changé le texte de "granita", différents guillemets aient fonctionné!
la modification manuelle de la chaîne que j'ai faite ressemble à ceci:
response = response.Replace("\"", "\\\"");
J'ai reproduit votre code avec quelques modifications mineures et il fonctionne très bien, à ma connaissance. Veuillez noter l'utilisation des instructions using
qui est une bonne pratique lorsque vous utilisez des objets IDisposable
et la manière dont l'objet est construit (j'ai utilisé le merveilleux json2csharp outil correspondant):
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; }
}