Search code examples
c#apihttpwebrequestjavascriptserializer

Parse json from web request response


Im trying to parse a http web response into an array or something so i can work with the information. This is the json response i get (+ a lot more, but i just censored the format):

{
    "meta": {
        "status": 200
    },
    "data": {
        "account": {
            "account_phone_number": "XXXXXXXX",
            "account_email": "MAIL@hotmail.com"
        },
        "user": {
            "id": "5f2b17e7836fc7010025aed3",
            "age": 23,
        }
    }
}

How can i write the "id" inside of "user" to console or a textbox?

This is my web request:

private void button1_Click(object sender, EventArgs e)
{
    const string WEBSERVICE_URL = "url_here";
    try
    {
        var webRequest = System.Net.WebRequest.Create(WEBSERVICE_URL);
        if (webRequest != null)
        {
            webRequest.Method = "GET";
            webRequest.Timeout = 12000;
            webRequest.ContentType = "application/json";
            webRequest.Headers.Add("x-auth-token", "Auth_token");

            using (System.IO.Stream s = webRequest.GetResponse().GetResponseStream())
            {
                using (System.IO.StreamReader sr = new System.IO.StreamReader(s))
                {
                    var jsonResponse = sr.ReadToEnd();
                    richTextBox1.AppendText(jsonResponse);
                }
            }
        }
    }
    catch (Exception ex)
    {
        richTextBox1.AppendText("No workie");
    }
}

I have tried the following:

public class Test
{
   public string meta {get;set;}
   public string data {get;set;}
}

and trying to serialize the json into a table as following:

JavaScriptSerializer js = new JavaScriptSerializer();
Test[] Tester = js.Deserialize<Test[]>(jsonResponse);
richTextBox1.AppendText(Tester);

But no luck. Can anyone please point me in the right direction here?


Solution

  • If you are able to use other serializer than JavaScriptSerializer then you can take advantage of partial deserializing.

    In case of Json.NET (formerly known as Newtonsoft Json) you have at least two options:

    SelectToken

    JObject semiParsedData = JObject.Parse(jsonResponse);
    string id = (string)semiParsedData.SelectToken("data.user.id");
    int age = (int)semiaParsedData.SelectToken("data.user.age");
    string email = (string)semiParsedData.SelectToken("data.account.account_email");
    
    • By calling the Parse method we will have a semi-parsed object.
    • On this object we can issue a Json Path query via the SelectToken.
      • The syntax is similar to XPath, which can be used to retrieve any arbitrary data form an XML.
      • More precisely it is a JPath.
    • SelectToken returns a JToken. From it you can retrieve data in several ways:
      • (string)semiParsedData.SelectToken("data.user.id")
      • semiParsedData.SelectToken("data.user.id").Value<string>()
      • semiParsedData.SelectToken("data.user.id").ToObject<string>()

    References:

    indexer operator

    JObject semiParsedData = JObject.Parse(jsonResponse);
    JToken data = semiParsedData["data"];
    
    JToken user = data["user"];
    string id = (string)user["id"];
    int age = (int)user["age"];
    
    JToken account = data["account"];
    string email = (string)account["account_email"];
    
    • JToken defines the following indexer operator, which is not really useful:
    public virtual JToken? this[object key]
    {
        get => throw new InvalidOperationException("Cannot access child value on {0}.".FormatWith(CultureInfo.InvariantCulture, GetType()));
        set => throw new InvalidOperationException("Cannot set child value on {0}.".FormatWith(CultureInfo.InvariantCulture, GetType()));
    }
    
    • On the other hand its derived class JObject overrides this to make that functionality useful:
      • (JObject derives from JContainer, which derives from JToken).
    public JToken? this[string propertyName]
    {
        get
        {
            ValidationUtils.ArgumentNotNull(propertyName, nameof(propertyName));
            JProperty? property = Property(propertyName, StringComparison.Ordinal);
            return property?.Value;
        }
        set
        {
            JProperty? property = Property(propertyName, StringComparison.Ordinal);
            if (property != null)
            {
                property.Value = value!;
            }
            else
            {
    #if HAVE_INOTIFY_PROPERTY_CHANGING
                OnPropertyChanging(propertyName);
    #endif
                Add(propertyName, value);
                OnPropertyChanged(propertyName);
            }
        }
    }
    
    • Here the Property method tries to get the requested entity from the _properties collection:
      • private readonly JPropertyKeyedCollection _properties

    Reference: