Parse JSON in C# Parse JSON in C# asp.net asp.net

Parse JSON in C#


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


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