views:

10020

answers:

3
+12  Q: 

Parse JSON in C#

A: 

Your GoogleSearchResults type has fields and properties that have the same name. Try renaming your fields with leading underscores (anything that will disambiguate between the two).

Andrew Hare
+8  A: 

[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 Deserialise<T>(string json)
{
    T obj = Activator.CreateInstance<T>();
    using (MemoryStream ms = new MemoryStream(Encoding.Unicode.GetBytes(json)))
    {
        DataContractJsonSerializer serializer = new DataContractJsonSerializer(obj.GetType());
        obj = (T)serializer.ReadObject(ms); // <== Your missing line
        return obj;
    } 
}

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


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;}
Andreas Grech
Thanks for the tip. I no longer get any errors although I'm not getting any output either. I've updated my code to show what I have so far.
EnderMB
are you using .net 2.0 or 3.5 ?
Andreas Grech
As far as I am aware this machine hasn't been updated to 3.5 yet, so I assume 2.0. I've already tried the get/set thing and it didn't work, but that part seems to be working great.
EnderMB
...hmm, but if I'm not mistaken, the `DataContractJsonSerializer` is available only in the 3.5 framework, no ?
Andreas Grech
That's odd, because Visual Studio doesn't seem to have a problem with recognising DataContractJsonSerializer in my code, yet it doesn't like using (get; set;).
EnderMB
Either way, I've upgraded this new machine to 3.5, so there shouldn't be any problems.
EnderMB
Check my latest update in my answer...i think I have figured out why nothing is being returned.
Andreas Grech
I've added this extra line of code and if I try to write g1.responseData.results I get "results[]" printed to my screen, with everything else printing as their names (e.g. g1.responseData printing "responseData" and g1 printing "GoogleSearchResults").
EnderMB
All fixed! I added a foreach loop and now it returns everything I need. 300 rep for you once I've double-checked everything.
EnderMB
+1  A: 

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);
    }
}
Joe Chung
I've just tried that, but I've just got the error "The type or namespace name 'IEnumerable' could not be found (are you missing a using directive or an assembly reference?)".
EnderMB
Nevermind, I was using System.Collections instead of System.Collection.Generic. It compiles perfectly with that code now, but what do I need to do to output the data?
EnderMB
Check my updated post because I found what was missing in your code
Andreas Grech