我正在尝试解析调用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响应:
现在程序正常运行,但它不存在。
答案 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; }
}