I'm trying to parse some JSON data from the Google AJAX Search API. I have this URL and I'd like to break it down so that the results are displayed. I've currently written this code, but I'm pretty lost in regards of what to do next, although there are a number of examples out there with simplified JSON strings.
Being new to C# and .NET in general I've struggled to get a genuine text output for my ASP.NET page so I've been recommended to give JSON.NET a try. Could anyone point me in the right direction to just simply writing some code that'll take in JSON from the Google AJAX Search API and print it out to the screen?
EDIT: ALL FIXED! All results are working fine. Thank you again Dreas Grech!
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.ServiceModel.Web;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
using System.IO;
using System.Text;
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
GoogleSearchResults g1 = new GoogleSearchResults();
const string json = #"{""responseData"": {""results"":[{""GsearchResultClass"":""GwebSearch"",""unescapedUrl"":""http://www.cheese.com/"",""url"":""http://www.cheese.com/"",""visibleUrl"":""www.cheese.com"",""cacheUrl"":""http://www.google.com/search?q\u003dcache:bkg1gwNt8u4J:www.cheese.com"",""title"":""\u003cb\u003eCHEESE\u003c/b\u003e.COM - All about \u003cb\u003echeese\u003c/b\u003e!."",""titleNoFormatting"":""CHEESE.COM - All about cheese!."",""content"":""\u003cb\u003eCheese\u003c/b\u003e - everything you want to know about it. Search \u003cb\u003echeese\u003c/b\u003e by name, by types of milk, by textures and by countries.""},{""GsearchResultClass"":""GwebSearch"",""unescapedUrl"":""http://en.wikipedia.org/wiki/Cheese"",""url"":""http://en.wikipedia.org/wiki/Cheese"",""visibleUrl"":""en.wikipedia.org"",""cacheUrl"":""http://www.google.com/search?q\u003dcache:n9icdgMlCXIJ:en.wikipedia.org"",""title"":""\u003cb\u003eCheese\u003c/b\u003e - Wikipedia, the free encyclopedia"",""titleNoFormatting"":""Cheese - Wikipedia, the free encyclopedia"",""content"":""\u003cb\u003eCheese\u003c/b\u003e is a food consisting of proteins and fat from milk, usually the milk of cows, buffalo, goats, or sheep. It is produced by coagulation of the milk \u003cb\u003e...\u003c/b\u003e""},{""GsearchResultClass"":""GwebSearch"",""unescapedUrl"":""http://www.ilovecheese.com/"",""url"":""http://www.ilovecheese.com/"",""visibleUrl"":""www.ilovecheese.com"",""cacheUrl"":""http://www.google.com/search?q\u003dcache:GBhRR8ytMhQJ:www.ilovecheese.com"",""title"":""I Love \u003cb\u003eCheese\u003c/b\u003e!, Homepage"",""titleNoFormatting"":""I Love Cheese!, Homepage"",""content"":""The American Dairy Association\u0026#39;s official site includes recipes and information on nutrition and storage of \u003cb\u003echeese\u003c/b\u003e.""},{""GsearchResultClass"":""GwebSearch"",""unescapedUrl"":""http://www.gnome.org/projects/cheese/"",""url"":""http://www.gnome.org/projects/cheese/"",""visibleUrl"":""www.gnome.org"",""cacheUrl"":""http://www.google.com/search?q\u003dcache:jvfWnVcSFeQJ:www.gnome.org"",""title"":""\u003cb\u003eCheese\u003c/b\u003e"",""titleNoFormatting"":""Cheese"",""content"":""\u003cb\u003eCheese\u003c/b\u003e uses your webcam to take photos and videos, applies fancy special effects and lets you share the fun with others. It was written as part of Google\u0026#39;s \u003cb\u003e...\u003c/b\u003e""}],""cursor"":{""pages"":[{""start"":""0"",""label"":1},{""start"":""4"",""label"":2},{""start"":""8"",""label"":3},{""start"":""12"",""label"":4},{""start"":""16"",""label"":5},{""start"":""20"",""label"":6},{""start"":""24"",""label"":7},{""start"":""28"",""label"":8}],""estimatedResultCount"":""14400000"",""currentPageIndex"":0,""moreResultsUrl"":""http://www.google.com/search?oe\u003dutf8\u0026ie\u003dutf8\u0026source\u003duds\u0026start\u003d0\u0026hl\u003den-GB\u0026q\u003dcheese""}}, ""responseDetails"": null, ""responseStatus"": 200}";
g1 = JSONHelper.Deserialise<GoogleSearchResults>(json);
Response.Write(g1.content);
}
}
public class JSONHelper
{
public static T Deserialise<T>(string json)
{
T obj = Activator.CreateInstance<T>();
MemoryStream ms = new MemoryStream(Encoding.Unicode.GetBytes(json));
DataContractJsonSerializer serialiser = new DataContractJsonSerializer(obj.GetType());
ms.Close();
return obj;
}
}
/// Deserialise from JSON
[Serializable]
public class GoogleSearchResults
{
public GoogleSearchResults() { }
public GoogleSearchResults(string _unescapedUrl, string _url, string _visibleUrl, string _cacheUrl, string _title, string _titleNoFormatting, string _content)
{
this.unescapedUrl = _unescapedUrl;
this.url = _url;
this.visibleUrl = _visibleUrl;
this.cacheUrl = _cacheUrl;
this.title = _title;
this.titleNoFormatting = _titleNoFormatting;
this.content = _content;
}
string _unescapedUrl;
string _url;
string _visibleUrl;
string _cacheUrl;
string _title;
string _titleNoFormatting;
string _content;
[DataMember]
public string unescapedUrl
{
get { return _unescapedUrl; }
set { _unescapedUrl = value; }
}
[DataMember]
public string url
{
get { return _url; }
set { _url = value; }
}
[DataMember]
public string visibleUrl
{
get { return _visibleUrl; }
set { _visibleUrl = value; }
}
[DataMember]
public string cacheUrl
{
get { return _cacheUrl; }
set { _cacheUrl = value; }
}
[DataMember]
public string title
{
get { return _title; }
set { _title = value; }
}
[DataMember]
public string titleNoFormatting
{
get { return _titleNoFormatting; }
set { _titleNoFormatting = value; }
}
[DataMember]
public string content
{
get { return _content; }
set { _content = value; }
}
}
The code currently compiles and runs perfectly, but isn't returning any results. Could someone help me with returning what I require, the results ready to print out to the screen?
Edit:
Json.NET works using the same JSON and classes as the example above.
GoogleSearchResults g1 = JsonConvert.DeserializeObject<GoogleSearchResults>(json);
Link: Serializing and Deserializing JSON with Json.NET
Related
C# - parsing json formatted data into nested hashtables
Parse JSON array
[Update]
I've just realized why you weren't receiving results back... you have a missing line in your Deserialize method. You were forgetting to assign the results to your obj :
public static T Deserialize<T>(string json)
{
using (MemoryStream ms = new MemoryStream(Encoding.Unicode.GetBytes(json)))
{
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(T));
return (T)serializer.ReadObject(ms);
}
}
Also, just for reference, here is the Serialize method :
public static string Serialize<T>(T obj)
{
DataContractJsonSerializer serializer = new DataContractJsonSerializer(obj.GetType());
using (MemoryStream ms = new MemoryStream())
{
serializer.WriteObject(ms, obj);
return Encoding.Default.GetString(ms.ToArray());
}
}
Edit
If you want to use Json.NET here are the equivalent Serialize/Deserialize methods to the code above..
Deserialize:
JsonConvert.DeserializeObject<T>(string json);
Serialize:
JsonConvert.SerializeObject(object o);
This are already part of Json.NET so you can just call them on the JsonConvert class.
Link: Serializing and Deserializing JSON with Json.NET
Now, the reason you're getting a StackOverflow is because of your Properties.
Take for example this one :
[DataMember]
public string unescapedUrl
{
get { return unescapedUrl; } // <= this line is causing a Stack Overflow
set { this.unescapedUrl = value; }
}
Notice that in the getter, you are returning the actual property (ie the property's getter is calling itself over and over again), and thus you are creating an infinite recursion.
Properties (in 2.0) should be defined like such :
string _unescapedUrl; // <= private field
[DataMember]
public string unescapedUrl
{
get { return _unescapedUrl; }
set { _unescapedUrl = value; }
}
You have a private field and then you return the value of that field in the getter, and set the value of that field in the setter.
Btw, if you're using the 3.5 Framework, you can just do this and avoid the backing fields, and let the compiler take care of that :
public string unescapedUrl { get; set;}
I found this approach which parse JSON into a dynamic object, it extends a DynamicObject and JavascriptConverter to turn the string into an object.
DynamicJsonObject
public class DynamicJsonObject : DynamicObject
{
private IDictionary<string, object> Dictionary { get; set; }
public DynamicJsonObject(IDictionary<string, object> dictionary)
{
this.Dictionary = dictionary;
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
result = this.Dictionary[binder.Name];
if (result is IDictionary<string, object>)
{
result = new DynamicJsonObject(result as IDictionary<string, object>);
}
else if (result is ArrayList && (result as ArrayList) is IDictionary<string, object>)
{
result = new List<DynamicJsonObject>((result as ArrayList).ToArray().Select(x => new DynamicJsonObject(x as IDictionary<string, object>)));
}
else if (result is ArrayList)
{
result = new List<object>((result as ArrayList).ToArray());
}
return this.Dictionary.ContainsKey(binder.Name);
}
}
Converter
public class DynamicJsonConverter : JavaScriptConverter
{
public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
{
if (dictionary == null)
throw new ArgumentNullException("dictionary");
if (type == typeof(object))
{
return new DynamicJsonObject(dictionary);
}
return null;
}
public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
{
throw new NotImplementedException();
}
public override IEnumerable<Type> SupportedTypes
{
get { return new ReadOnlyCollection<Type>(new List<Type>(new Type[] { typeof(object) })); }
}
}
Usage (sample json):
JavaScriptSerializer jss = new JavaScriptSerializer();
jss.RegisterConverters(new JavaScriptConverter[] { new DynamicJsonConverter() });
dynamic glossaryEntry = jss.Deserialize(json, typeof(object)) as dynamic;
Console.WriteLine("glossaryEntry.glossary.title: " + glossaryEntry.glossary.title);
Console.WriteLine("glossaryEntry.glossary.GlossDiv.title: " + glossaryEntry.glossary.GlossDiv.title);
Console.WriteLine("glossaryEntry.glossary.GlossDiv.GlossList.GlossEntry.ID: " + glossaryEntry.glossary.GlossDiv.GlossList.GlossEntry.ID);
Console.WriteLine("glossaryEntry.glossary.GlossDiv.GlossList.GlossEntry.GlossDef.para: " + glossaryEntry.glossary.GlossDiv.GlossList.GlossEntry.GlossDef.para);
foreach (var also in glossaryEntry.glossary.GlossDiv.GlossList.GlossEntry.GlossDef.GlossSeeAlso)
{
Console.WriteLine("glossaryEntry.glossary.GlossDiv.GlossList.GlossEntry.GlossDef.GlossSeeAlso: " + also);
}
This method has to return true, otherwise it will throw an error. E.g. you can throw an error if a key does not exist.
Returning true and emptying result will return an empty value rather than throwing an error.
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
if (!this.Dictionary.ContainsKey(binder.Name))
{
result = "";
}
else
{
result = this.Dictionary[binder.Name];
}
if (result is IDictionary<string, object>)
{
result = new DynamicJsonObject(result as IDictionary<string, object>);
}
else if (result is ArrayList && (result as ArrayList) is IDictionary<string, object>)
{
result = new List<DynamicJsonObject>((result as ArrayList).ToArray().Select(x => new DynamicJsonObject(x as IDictionary<string, object>)));
}
else if (result is ArrayList)
{
result = new List<object>((result as ArrayList).ToArray());
}
return true; // this.Dictionary.ContainsKey(binder.Name);
}
Your data class doesn't match the JSON object. Use this instead:
[DataContract]
public class GoogleSearchResults
{
[DataMember]
public ResponseData responseData { get; set; }
}
[DataContract]
public class ResponseData
{
[DataMember]
public IEnumerable<Results> results { get; set; }
}
[DataContract]
public class Results
{
[DataMember]
public string unescapedUrl { get; set; }
[DataMember]
public string url { get; set; }
[DataMember]
public string visibleUrl { get; set; }
[DataMember]
public string cacheUrl { get; set; }
[DataMember]
public string title { get; set; }
[DataMember]
public string titleNoFormatting { get; set; }
[DataMember]
public string content { get; set; }
}
Also, you don't have to instantiate the class to get its type for deserialization:
public static T Deserialise<T>(string json)
{
using (var ms = new MemoryStream(Encoding.Unicode.GetBytes(json)))
{
var serialiser = new DataContractJsonSerializer(typeof(T));
return (T)serialiser.ReadObject(ms);
}
}
I just think the whole example would be useful. This is the example for this problem.
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.ServiceModel.Web;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
using System.IO;
using System.Text;
using System.Collections.Generic;
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
GoogleSearchResults g1 = new GoogleSearchResults();
const string json = #"{""responseData"": {""results"":[{""GsearchResultClass"":""GwebSearch"",""unescapedUrl"":""http://www.cheese.com/"",""url"":""http://www.cheese.com/"",""visibleUrl"":""www.cheese.com"",""cacheUrl"":""http://www.google.com/search?q\u003dcache:bkg1gwNt8u4J:www.cheese.com"",""title"":""\u003cb\u003eCHEESE\u003c/b\u003e.COM - All about \u003cb\u003echeese\u003c/b\u003e!."",""titleNoFormatting"":""CHEESE.COM - All about cheese!."",""content"":""\u003cb\u003eCheese\u003c/b\u003e - everything you want to know about it. Search \u003cb\u003echeese\u003c/b\u003e by name, by types of milk, by textures and by countries.""},{""GsearchResultClass"":""GwebSearch"",""unescapedUrl"":""http://en.wikipedia.org/wiki/Cheese"",""url"":""http://en.wikipedia.org/wiki/Cheese"",""visibleUrl"":""en.wikipedia.org"",""cacheUrl"":""http://www.google.com/search?q\u003dcache:n9icdgMlCXIJ:en.wikipedia.org"",""title"":""\u003cb\u003eCheese\u003c/b\u003e - Wikipedia, the free encyclopedia"",""titleNoFormatting"":""Cheese - Wikipedia, the free encyclopedia"",""content"":""\u003cb\u003eCheese\u003c/b\u003e is a food consisting of proteins and fat from milk, usually the milk of cows, buffalo, goats, or sheep. It is produced by coagulation of the milk \u003cb\u003e...\u003c/b\u003e""},{""GsearchResultClass"":""GwebSearch"",""unescapedUrl"":""http://www.ilovecheese.com/"",""url"":""http://www.ilovecheese.com/"",""visibleUrl"":""www.ilovecheese.com"",""cacheUrl"":""http://www.google.com/search?q\u003dcache:GBhRR8ytMhQJ:www.ilovecheese.com"",""title"":""I Love \u003cb\u003eCheese\u003c/b\u003e!, Homepage"",""titleNoFormatting"":""I Love Cheese!, Homepage"",""content"":""The American Dairy Association\u0026#39;s official site includes recipes and information on nutrition and storage of \u003cb\u003echeese\u003c/b\u003e.""},{""GsearchResultClass"":""GwebSearch"",""unescapedUrl"":""http://www.gnome.org/projects/cheese/"",""url"":""http://www.gnome.org/projects/cheese/"",""visibleUrl"":""www.gnome.org"",""cacheUrl"":""http://www.google.com/search?q\u003dcache:jvfWnVcSFeQJ:www.gnome.org"",""title"":""\u003cb\u003eCheese\u003c/b\u003e"",""titleNoFormatting"":""Cheese"",""content"":""\u003cb\u003eCheese\u003c/b\u003e uses your webcam to take photos and videos, applies fancy special effects and lets you share the fun with others. It was written as part of Google\u0026#39;s \u003cb\u003e...\u003c/b\u003e""}],""cursor"":{""pages"":[{""start"":""0"",""label"":1},{""start"":""4"",""label"":2},{""start"":""8"",""label"":3},{""start"":""12"",""label"":4},{""start"":""16"",""label"":5},{""start"":""20"",""label"":6},{""start"":""24"",""label"":7},{""start"":""28"",""label"":8}],""estimatedResultCount"":""14400000"",""currentPageIndex"":0,""moreResultsUrl"":""http://www.google.com/search?oe\u003dutf8\u0026ie\u003dutf8\u0026source\u003duds\u0026start\u003d0\u0026hl\u003den-GB\u0026q\u003dcheese""}}, ""responseDetails"": null, ""responseStatus"": 200}";
g1 = JSONHelper.Deserialise<GoogleSearchResults>(json);
foreach (Pages x in g1.responseData.cursor.pages)
{
// Anything you want to get
Response.Write(x.label);
}
}
}
public class JSONHelper
{
public static T Deserialise<T>(string json)
{
using (var ms = new MemoryStream(Encoding.Unicode.GetBytes(json)))
{
var serialiser = new DataContractJsonSerializer(typeof(T));
return (T)serialiser.ReadObject(ms);
}
}
public static string Serialize<T>(T obj)
{
DataContractJsonSerializer serializer = new DataContractJsonSerializer(obj.GetType());
using (MemoryStream ms = new MemoryStream())
{
serializer.WriteObject(ms, obj);
return Encoding.Default.GetString(ms.ToArray());
}
}
}
[DataContract]
public class GoogleSearchResults
{
[DataMember]
public ResponseData responseData { get; set; }
[DataMember]
public string responseStatus { get; set; }
}
public class ResponseData
{
[DataMember]
public Cursor cursor { get; set; }
[DataMember]
public IEnumerable<Results> results { get; set; }
}
[DataContract]
public class Cursor
{
[DataMember]
public IEnumerable<Pages> pages { get; set; }
}
[DataContract]
public class Pages
{
[DataMember]
public string start { get; set; }
[DataMember]
public string label { get; set; }
}
[DataContract]
public class Results
{
[DataMember]
public string unescapedUrl { get; set; }
[DataMember]
public string url { get; set; }
[DataMember]
public string visibleUrl { get; set; }
[DataMember]
public string cacheUrl { get; set; }
[DataMember]
public string title { get; set; }
[DataMember]
public string titleNoFormatting { get; set; }
[DataMember]
public string content { get; set; }
}
I tried to use the code above but didn't work. The JSON structure returned by Google is so different and there is a very important miss in the helper function: a call to DataContractJsonSerializer.ReadObject() that actually deserializes the JSON data into the object.
Here is the code that WORKS in 2011:
using System;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
using System.IO;
using System.Text;
using System.Collections.Generic;
namespace <YOUR_NAMESPACE>
{
public class JSONHelper
{
public static T Deserialise<T>(string json)
{
T obj = Activator.CreateInstance<T>();
MemoryStream ms = new MemoryStream(Encoding.Unicode.GetBytes(json));
DataContractJsonSerializer serialiser = new DataContractJsonSerializer(obj.GetType());
obj = (T)serialiser.ReadObject(ms);
ms.Close();
return obj;
}
}
public class Result
{
public string GsearchResultClass { get; set; }
public string unescapedUrl { get; set; }
public string url { get; set; }
public string visibleUrl { get; set; }
public string cacheUrl { get; set; }
public string title { get; set; }
public string titleNoFormatting { get; set; }
public string content { get; set; }
}
public class Page
{
public string start { get; set; }
public int label { get; set; }
}
public class Cursor
{
public string resultCount { get; set; }
public Page[] pages { get; set; }
public string estimatedResultCount { get; set; }
public int currentPageIndex { get; set; }
public string moreResultsUrl { get; set; }
public string searchResultTime { get; set; }
}
public class ResponseData
{
public Result[] results { get; set; }
public Cursor cursor { get; set; }
}
public class GoogleSearchResults
{
public ResponseData responseData { get; set; }
public object responseDetails { get; set; }
public int responseStatus { get; set; }
}
}
To get the content of the first result, do:
GoogleSearchResults googleResults = new GoogleSearchResults();
googleResults = JSONHelper.Deserialise<GoogleSearchResults>(jsonData);
string contentOfFirstResult = googleResults.responseData.results[0].content;
Thank you all for your help.
This is my final version, and it works thanks to your combined help !
I am only showing the changes i made, all the rest is taken from Joe Chung's work
public class GoogleSearchResults
{
[DataMember]
public ResponseData responseData { get; set; }
[DataMember]
public string responseDetails { get; set; }
[DataMember]
public int responseStatus { get; set; }
}
and
[DataContract]
public class ResponseData
{
[DataMember]
public List<Results> results { get; set; }
}
Google Map API request and parse DirectionsResponse with C#, change the json in your url to xml
and use the following code to turn the result into a usable C# Generic List Object.
Took me a while to make. But here it is
var url = String.Format("http://maps.googleapis.com/maps/api/directions/xml?...");
var result = new System.Net.WebClient().DownloadString(url);
var doc = XDocument.Load(new StringReader(result));
var DirectionsResponse = doc.Elements("DirectionsResponse").Select(l => new
{
Status = l.Elements("status").Select(q => q.Value).FirstOrDefault(),
Route = l.Descendants("route").Select(n => new
{
Summary = n.Elements("summary").Select(q => q.Value).FirstOrDefault(),
Leg = n.Elements("leg").ToList().Select(o => new
{
Step = o.Elements("step").Select(p => new
{
Travel_Mode = p.Elements("travel_mode").Select(q => q.Value).FirstOrDefault(),
Start_Location = p.Elements("start_location").Select(q => new
{
Lat = q.Elements("lat").Select(r => r.Value).FirstOrDefault(),
Lng = q.Elements("lng").Select(r => r.Value).FirstOrDefault()
}).FirstOrDefault(),
End_Location = p.Elements("end_location").Select(q => new
{
Lat = q.Elements("lat").Select(r => r.Value).FirstOrDefault(),
Lng = q.Elements("lng").Select(r => r.Value).FirstOrDefault()
}).FirstOrDefault(),
Polyline = p.Elements("polyline").Select(q => new
{
Points = q.Elements("points").Select(r => r.Value).FirstOrDefault()
}).FirstOrDefault(),
Duration = p.Elements("duration").Select(q => new
{
Value = q.Elements("value").Select(r => r.Value).FirstOrDefault(),
Text = q.Elements("text").Select(r => r.Value).FirstOrDefault(),
}).FirstOrDefault(),
Html_Instructions = p.Elements("html_instructions").Select(q => q.Value).FirstOrDefault(),
Distance = p.Elements("distance").Select(q => new
{
Value = q.Elements("value").Select(r => r.Value).FirstOrDefault(),
Text = q.Elements("text").Select(r => r.Value).FirstOrDefault(),
}).FirstOrDefault()
}).ToList(),
Duration = o.Elements("duration").Select(p => new
{
Value = p.Elements("value").Select(q => q.Value).FirstOrDefault(),
Text = p.Elements("text").Select(q => q.Value).FirstOrDefault()
}).FirstOrDefault(),
Distance = o.Elements("distance").Select(p => new
{
Value = p.Elements("value").Select(q => q.Value).FirstOrDefault(),
Text = p.Elements("text").Select(q => q.Value).FirstOrDefault()
}).FirstOrDefault(),
Start_Location = o.Elements("start_location").Select(p => new
{
Lat = p.Elements("lat").Select(q => q.Value).FirstOrDefault(),
Lng = p.Elements("lng").Select(q => q.Value).FirstOrDefault()
}).FirstOrDefault(),
End_Location = o.Elements("end_location").Select(p => new
{
Lat = p.Elements("lat").Select(q => q.Value).FirstOrDefault(),
Lng = p.Elements("lng").Select(q => q.Value).FirstOrDefault()
}).FirstOrDefault(),
Start_Address = o.Elements("start_address").Select(q => q.Value).FirstOrDefault(),
End_Address = o.Elements("end_address").Select(q => q.Value).FirstOrDefault()
}).ToList(),
Copyrights = n.Elements("copyrights").Select(q => q.Value).FirstOrDefault(),
Overview_polyline = n.Elements("overview_polyline").Select(q => new
{
Points = q.Elements("points").Select(r => r.Value).FirstOrDefault()
}).FirstOrDefault(),
Waypoint_Index = n.Elements("waypoint_index").Select(o => o.Value).ToList(),
Bounds = n.Elements("bounds").Select(q => new
{
SouthWest = q.Elements("southwest").Select(r => new
{
Lat = r.Elements("lat").Select(s => s.Value).FirstOrDefault(),
Lng = r.Elements("lng").Select(s => s.Value).FirstOrDefault()
}).FirstOrDefault(),
NorthEast = q.Elements("northeast").Select(r => new
{
Lat = r.Elements("lat").Select(s => s.Value).FirstOrDefault(),
Lng = r.Elements("lng").Select(s => s.Value).FirstOrDefault()
}).FirstOrDefault(),
}).FirstOrDefault()
}).FirstOrDefault()
}).FirstOrDefault();
I hope this will help someone.
Related
Hello I have problem with deserializing IRestResponse.Content JSON response.
{
"49":
{
"9345": "2018-10-11",
"106": null,
"107": "4222238842",
"108": "CompanyName",
"8210": "2018-11-11/1",
"110": "00-300",
"109": "Street",
"112": "Country",
"18418": null,
"18420": "S\u0141ON",
"18422": "OtherString",
"9338": null,
"111": "City"
}
}
I have tried some webpage's or built in VisualStudio converter but It gives my something like this.
public class Rootobject
{
public _49 _49 { get; set; }
}
public class _49
{
public string _9345 { get; set; }
public object _106 { get; set; }
public string _107 { get; set; }
public string _108 { get; set; }
public string _8210 { get; set; }
public string _110 { get; set; }
public string _109 { get; set; }
public string _112 { get; set; }
public object _18418 { get; set; }
public string _18420 { get; set; }
public string _18422 { get; set; }
public object _9338 { get; set; }
public string _111 { get; set; }
}
This look's ok but In my case those JSON files have dynamic property names and can have another "int" values. Also the nested content inside "49" can have less or more values.
I am especially interested in gathering "49" << this value to variable.
I also have tried something like this, but doesn't work either:
public class DeserializeJsonContent
{
public Dictionary<object, Dictionary<object, object>> values { get; set; }
}
Simplified code sample
public List<T> JSONDeserialize<T>(IRestResponse response) where T : new()
{
var responseData = client.Deserialize<List<T>>(response);
var ListDeserializedData = responseData.Data.ToList<T>();
return ListDeserializedData;
}
....
var response = rest.client.Execute(request);
if (response.IsSuccessful)
{
var obj = rest.JSONDeserialize<DeserializeJsonContent>(response);
}
obj has count 1 but vals = null
Edit after Solve:
I still have no idea why my deserialized class doesn't work in this case (I am using it in many other json deserialization response's)
Thanks to xdtTransform answer I have tried and all of those worked
var obj2 = JsonConvert.DeserializeObject<Dictionary<string, Dictionary<object, object>>>(response.Content);
var obj3 = JsonConvert.DeserializeObject<Dictionary<string, Dictionary<string, string>>>(response.Content);
var obj4 = JsonConvert.DeserializeObject<Dictionary<int, Dictionary<string, string>>>(response.Content);
var obj5 = JsonConvert.DeserializeObject<Dictionary<object, Dictionary<string, string>>>(response.Content);
var obj6 = JsonConvert.DeserializeObject<Dictionary<object, Dictionary<object, object>>>(response.Content);
var obj7 = JsonConvert.DeserializeObject<Dictionary<object, Dictionary<int, object>>>(response.Content);
Then just
var value = obj2.First().Key;
Using Newtonsoft.Json, You can directly deserialize to Dictionary<string,Dictionary<string,string>> like :
var obj = JsonConvert.DeserializeObject<Dictionary<string,Dictionary<string,string>>>(input);
If you need it to be in your custom type, you should declare this type like :
public class WrapperType : Dictionary<string,Dictionary<string,string>>{}
Then the Deserialisation stay the same:
var obj = JsonConvert.DeserializeObject<WrapperType>(input);
Updated demo
Please deserialize response content
string data = response.Content;
var responseData = client.Deserialize<List<T>>(data);
I'm trying to implement usage of ServiceStack for faster JSON serialization/deserialization in my .NET MVC4 application.
I have following for deserializing AJAX requests:
Global.asax.cs:
// Remove and JsonValueProviderFactory and add JsonServiceStackValueProviderFactory
ValueProviderFactories.Factories.Remove(ValueProviderFactories.Factories.OfType<JsonValueProviderFactory>().FirstOrDefault());
ValueProviderFactories.Factories.Add(new JsonServiceStackValueProviderFactory());
public sealed class JsonServiceStackValueProviderFactory : ValueProviderFactory
{
public override IValueProvider GetValueProvider(ControllerContext controllerContext)
{
if (controllerContext == null)
throw new ArgumentNullException("controllerContext");
if (!controllerContext.HttpContext.Request.ContentType.StartsWith("application/json", StringComparison.OrdinalIgnoreCase))
return null;
var reader = new StreamReader(controllerContext.HttpContext.Request.InputStream).BaseStream;
return new DictionaryValueProvider<object>(
ServiceStack.Text.JsonSerializer.DeserializeFromStream<Dictionary<string, object>>(reader).AsExpandoObject(),
CultureInfo.CurrentCulture);
}
}
// http://nine69.wordpress.com/2013/02/02/asp-net-mvc-series-high-performance-json-parser-for-asp-net-mvc/
public static class CollectionExtensions
{
public static ExpandoObject AsExpandoObject(this IDictionary<string, object> dictionary)
{
var epo = new ExpandoObject();
var epoDic = epo as IDictionary<string, object>;
foreach (var item in dictionary)
{
bool processed = false;
if (item.Value is IDictionary<string, object>)
{
epoDic.Add(item.Key, AsExpandoObject((IDictionary<string, object>) item.Value));
processed = true;
}
else if (item.Value is ICollection)
{
var itemList = new List<object>();
foreach (object item2 in (ICollection) item.Value)
if (item2 is IDictionary<string, object>)
itemList.Add(AsExpandoObject((IDictionary<string, object>) item2));
else
itemList.Add(AsExpandoObject(new Dictionary<string, object> {{"Unknown", item2}}));
if (itemList.Count > 0)
{
epoDic.Add(item.Key, itemList);
processed = true;
}
}
if (!processed)
epoDic.Add(item);
}
return epo;
}
}
I am trying to deserialize an object which looks like:
[DataContract]
public class PlaylistItemDto
{
[DataMember(Name = "playlistId")]
public Guid PlaylistId { get; set; }
[DataMember(Name = "id")]
public Guid Id { get; set; }
[DataMember(Name = "sequence")]
public int Sequence { get; set; }
// Store Title on PlaylistItem as well as on Video because user might want to rename PlaylistItem.
[DataMember(Name = "title")]
public string Title { get; set; }
[DataMember(Name = "video")]
public VideoDto Video { get; set; }
[DataMember(Name = "cid")]
public string Cid { get; set; }
public PlaylistItemDto()
{
Id = Guid.Empty;
Title = string.Empty;
}
public static PlaylistItemDto Create(PlaylistItem playlistItem)
{
PlaylistItemDto playlistItemDto = Mapper.Map<PlaylistItem, PlaylistItemDto>(playlistItem);
return playlistItemDto;
}
public static List<PlaylistItemDto> Create(IEnumerable<PlaylistItem> playlistItems)
{
List<PlaylistItemDto> playlistItemDtos = Mapper.Map<IEnumerable<PlaylistItem>, List<PlaylistItemDto>>(playlistItems);
return playlistItemDtos;
}
}
[DataContract]
public class VideoDto
{
[DataMember(Name = "id")]
public string Id { get; set; }
[DataMember(Name = "title")]
public string Title { get; set; }
[DataMember(Name = "duration")]
public int Duration { get; set; }
[DataMember(Name = "author")]
public string Author { get; set; }
[DataMember(Name = "highDefinition")]
public bool HighDefinition { get; set; }
public VideoDto()
{
Id = string.Empty;
Title = string.Empty;
Author = string.Empty;
}
/// <summary>
/// Converts a Domain object to a DTO
/// </summary>
public static VideoDto Create(Video video)
{
VideoDto videoDto = Mapper.Map<Video, VideoDto>(video);
return videoDto;
}
public static List<VideoDto> Create(IEnumerable<Video> videos)
{
List<VideoDto> videoDtos = Mapper.Map<IEnumerable<Video>, List<VideoDto>>(videos);
return videoDtos;
}
}
The first level is deserialized correctly, but the Video object is null. I have been scouring the web for additional documentation, but haven't come up with much. I've found these articles which seem to be relevant:
How to get ServiceStack to serialize / deserialize an expando object with correct types
Deserializing JSON into Object
But the first doesn't provide an example -- only mentions some changes to the new versions of ServiceStack. The second shows how to deserialize, but doesn't handle a Stream or ExpandoObjects. The first hints that ExpandoObjects might not be fully supported.
I feel like I am trying to deserialize a pretty simple object. Is there any support for nested levels of objects in ServiceStack? Thanks
You can see full source on GitHub if that is helpful: https://github.com/MeoMix/StreamusServer/blob/development/Streamus/Global.asax.cs
Trying to get the result from a webservice call to return a Model. I eep getting the error:
Cannot deserialize the current JSON array (e.g. [1,2,3]) into type 'CI.Models.Schedule' because the type requires a JSON object (e.g. {"name":"value"}) to deserialize correctly.
public Schedule getCourseSchedule()
{
var obj = new
{
States = new[] { new { State = "MX" } },
Zip = "",
Miles = "",
PaginationStart = 1,
PaginationLimit = 3
};
using (var client = new WebClient())
{
client.Headers[HttpRequestHeader.ContentType] = "apoplication/json";
var url = "http://192.168.1.198:15014/ShoppingCart2/CourseSchedule";
var json = JsonConvert.SerializeObject(obj);
byte[] data = Encoding.UTF8.GetBytes(json);
byte[] result = client.UploadData(url, data);
string returnjson = Encoding.UTF8.GetString(result);
Schedule sched = JsonConvert.DeserializeObject<Schedule>(returnjson);
return sched;
}
}
Schedule Model:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Globalization;
namespace CI.Models
{
public class Schedule
{
public IEnumerable<Course> Courses { get; set; }
}
public class Course
{
/*
JSON Data returned from web service:
{
"ProgramGroup":"MR",
"ProgramCode":"RM",
"EventCode":"20160901MXMR",
"FormalDate":"September 1-2, 2016",
"StartDate":"2016\/09\/01",
"Price":5,
"LocName":"WB Hotel",
"LocAddress":"Av. Speedy Gonzales 220",
"LocCity":"Monterrey",
"LocState":"MX",
"LocZipCode":null,
"LicenseeURL":null,
"AgendaURL":"NA",
"SeatsAreAvailable":"2",
"GeneralInfoHTML":"General Info goes here.",
"GateKeeperHTML":null,
"EventType":"SS",
"TotalCourses":3
}
*/
public string ProgramGroup { get; set; }
public string ProgramCode { get; set; }
public string EventCode { get; set; }
public string FormalDate { get { return FormalDate; } set { FormalDate = convertFormalDateToSpanish(value); } }
public string StartDate { get; set; }
public double Price { get; set; }
public string LocName { get; set; }
public string LocAddress { get; set; }
public string LocCity { get ; set; }
public string LocState { get; set; }
public string LocZipCode { get; set; }
public string LicenseeURL { get; set; }
public string AgendaURL { get { return AgendaURL; } set { AgendaURL = buildAgendaLink(value); } }
public string SeatsAreAvailable { get; set; }
public string GeneralInfoHTML { get; set; }
public string GateKeeperHTML { get; set; }
public string EventType { get; set; }
public int TotalCourses { get; set; }
public string convertFormalDateToSpanish(string val)
{
DateTime TheDate = DateTime.Parse(StartDate);
string[] FormalDate = val.Split(" ".ToCharArray());
CultureInfo ci = new CultureInfo("es-ES");
string _Date = FormalDate[1].Replace("-", " al ").Replace(",", "");
string _Month = ci.TextInfo.ToTitleCase(TheDate.ToString("MMMM", ci));
val = string.Concat(_Date, " ", _Month);
return val;
}
private string buildAgendaLink(string val)
{
if (val.Trim() != "")
{
val = string.Concat("Agenda");
}
else
{
val = "Agenda";
}
return val;
}
}
}
Your server returns an array. Just try
Course[] courses = JsonConvert.DeserializeObject<Course[]>(returnjson);
Note that this is not an answer to your original problem, but I added it like an answer in order to explain my comment above with some actual code.
First problem with your code is that FormalDate and AgendaUrl properties simply won't work. Accessing them will result in a StackOverflowException, because you basically defined them recursively.
A property is merely syntax sugar for two separate getter/setter methods, so by writing this:
public class Course
{
public string FormalDate
{
get { return FormalDate; }
}
}
You are basically writing this:
public class Course
{
public string GetFormalDate()
{
// recursive call, with no terminating condition,
// will infinitely call itself until there is no
// more stack to store context data (and CLR
// will then throw an exception)
return GetFormalDate();
}
}
To fix that, you need to add an actual backing field, e.g.:
public class Course
{
private string _formalDate; // <-- this is a backing field;
// and this property uses the backing field to read/store data
public string FormalDate
{
get { return _formalDate; }
set { _formalDate = convertFormalDateToSpanish(value); }
}
}
Additionally, it's unusual for a property getter to return a different value than the one set through a setter. In other words, I would never expect this from a class:
var course = new Course();
course.StartDate = "2016/09/01";
course.FormalDate = "September 1-2, 2016";
Console.WriteLine(course.FormalDate); // prints "1 al 2 Septiembre" ?
I would rather move this functionality into a different class, or at least create different properties which return these values:
public class CourseInfo
{
// this is now a "dumb" auto-implemented property
// (no need for a backing field anymore)
public string FormalDate { get; set; }
// this read-only property returns the converted value
public string LocalizedFormalDate
{
get
{
return convertFormalDateToSpanish(FormalDate);
}
}
}
Trying to deserialize an instance of this class
[Serializable]
public class InstalledMeter : ISerializable
{
public string Description { get; set; }
public double Latitude { get; set; }
public double Longitude { get; set; }
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("Description", Description);
info.AddValue("Latitude", Latitude);
info.AddValue("Longitude", Longitude);
}
}
The instance:
new InstalledMeter {Description = "Something", Latitude = 0.0, Longitude = 0.0};
My Serialization methods
public static class SerializeString
{
public static string SerializeObject<T>(this T toSerialize)
{
var xmlSerializer = new XmlSerializer(toSerialize.GetType());
var textWriter = new StringWriter();
xmlSerializer.Serialize(textWriter, toSerialize);
return textWriter.ToString();
}
public static T XmlDeserializeFromString<T>(this string objectData)
{
return (T)XmlDeserializeFromString(objectData, typeof(T));
}
public static object XmlDeserializeFromString(string objectData, Type type)
{
var serializer = new XmlSerializer(type);
object result;
using (TextReader reader = new StringReader(objectData))
{
result = serializer.Deserialize(reader);
}
return result;
}
}
But when I serialize the object it has these values
(guessing an answer based on your previous question - Error passing parameters to mvvmcross viewmodels)
If you are doing this in MvvmCross, then I would avoid this xml problem altogether and just use JSON serialization
var jsonText = JSONConvert.SerializeObject(installedMeter);
and
var installedMeter = JSONConvert.DeserializeObject<InstalledMeter>(jsonText);
using just:
public class InstalledMeter
{
public string Description { get; set; }
public double Latitude { get; set; }
public double Longitude { get; set; }
}
I'm trying to deserialize a reponse from a REST API.
"<FieldListDTO xmlns=\"api.playcento.com/1.0\" xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\">
<Allfield>
<FieldDTO>
<Fieldname>Mobile nr</Fieldname>
<Fieldtype>T</Fieldtype>
<Fieldvalue>003241234578</Fieldvalue>
<Fk_id_page>CP584ea74ce5ad4e2d8561d75fc6944f96</Fk_id_page>
<Id_field>FI152dcde5ef9849898b12d6a3f2cdb4ee</Id_field>
<Required>true</Required>
</FieldDTO>
</Allfield>
<Totalcount>1</Totalcount>
</FieldListDTO>"
The Field class:
namespace PlaycentoAPI.Model
{
[XmlRoot("FieldListDTO",Namespace = "api.playcento.com/1.0")]
[XmlType("FieldListDTO")]
public class FieldListDTO
{
public FieldListDTO() { }
[XmlElement("Totalcount")]
public int TotalCount { get; set; }
[XmlArray("Allfield")]
[XmlArrayItem("FieldDTO", typeof(Field))]
public Field[] Field { get; set; }
}
[XmlRoot("FieldDTO", Namespace = "api.paycento.com/1.0")]
[XmlType("FieldDTO")]
public class Field
{
public Field()
{
}
[XmlElement("Id_field")]
public string ID_Field { get; set; }
[XmlElement("Fieldtype")]
public string FieldType { get; set; }
[XmlElement("Fk_id_page")]
public string FK_ID_PAGE { get; set; }
[XmlElement("Required")]
public bool Required { get; set; }
[XmlElement("Fieldname")]
public string FieldName { get; set; }
[XmlElement("Fieldvalue")]
public string FieldValue { get; set; }
}
}
My code which calls the API and deserializes it:
string response = Helper.PerformAndReadHttpRequest(uri, "GET", "");
FieldListDTO myObject;
XmlReaderSettings settings = new XmlReaderSettings();
using (StringReader textReader = new StringReader(response))
{
using (XmlReader xmlReader = XmlReader.Create(textReader, settings))
{
XmlSerializer mySerializer = new XmlSerializer(typeof(FieldListDTO));
myObject = (FieldListDTO)mySerializer.Deserialize(xmlReader);
}
}
return myObject.Field;
In my actual response, I'm getting back 14 FieldDTO's. After deserializing the xml, FieldListDTO myObject contains TotalCount = 14 and Field is an array containing 14 Field's. But all the properties of these fields are NULL (or false).
I'm using the same method for several other API calls. I've compared the classes and the only difference that I see is that the class (Field) has an bool property. So I thought that was the problem. I've changed the bool property to a string but still all the properties were NULL after deserialization.
First thing to catch my eye is that the namespace in your FieldDTO class doesn't match the one in the XML document.
"api.paycento.com/1.0"
"api.playcento.com/1.0"