Alma
Alma

Reputation: 4390

Parsing JSON fails on newlines

I am getting response back in JSON format. I am using jsSerializer to get the value of the field from the JSON. It is working in most part but I am not sure why in one situation the coming back JSON has \n in it, and for this reason, jsSerializer is not working.

This is my code:

 protected void btnStats_Click(object sender, EventArgs e)
    {

        IRestResponse response = GetStats();//Stats provide you with the summary of the events that occur with your messages. 

        JavaScriptSerializer jsSerializer = new JavaScriptSerializer();

        var jsobj = jsSerializer.Deserialize<dynamic>(response.Content);


        int total_count= Convert.ToInt32(jsobj[0]["total_count"]); //I am getting error

and this is the method that is returning JSON:

    public static IRestResponse GetStats()
    {
        RestClient client = new RestClient();
        client.BaseUrl = "https://api.mailgun.net/v2";
        client.Authenticator =
                new HttpBasicAuthenticator("api",
                                           "key");
        RestRequest request = new RestRequest();
        request.AddParameter("domain",
                             "messenger.test.com", ParameterType.UrlSegment);
        request.Resource = "{domain}/stats";
        request.AddParameter("event", "sent");
        request.AddParameter("event", "opened");
        request.AddParameter("skip", 1);
        request.AddParameter("limit", 2);
        return client.Execute(request);
    }

I have sevaral of these methods that are working fine and only difference that I found is the JSON format that is in (response.Content) has \n. I haven't done anything in order to remove \n; it just wasn't there.

This is the JSON I am getting from that code:

   "{\n  \"total_count\": 54,\n  \"items\": [\n    {\n      \"total_count\": 715,\n      \"created_at\": \"Mon, 04 Nov 2013 00:00:00 GMT\",\n      \"tags\": {},\n      \"id\": \"5276e3835b8917d8268a6df1\",\n      \"event\": \"opened\"\n    },\n    {\n      \"total_count\": 688,\n      \"created_at\": \"Sun, 03 Nov 2013 00:00:00 GMT\",\n      \"tags\": {},\n      \"id\": \"527592035b8917d8268a1348\",\n      \"event\": \"sent\"\n    }\n  ]\n}"

and in the other method that is working fine, I get this kind of JSON:

 "[{\"unique\": {\"link\": 1}, \"total\": 35, \"recipient\": \"[email protected]\"}, {\"unique\": {\"link\": 1}, \"total\": 22, \"recipient\": \"[email protected]\"}]"

Upvotes: 0

Views: 2205

Answers (1)

Trevor Elliott
Trevor Elliott

Reputation: 11252

Formatted JSON strings can have newlines and other whitespace formatting in them. This will show up as \n in the Visual Studio debugger.

It will parse the same as a JSON string without extra whitespace.

The error is in your code, not in the JSON. You are trying to use an indexer on the dynamic value. But the dynamic value is not an array so it does not support an indexer. It is an object. You must access the properties manually, such as:

jsobj["total_count"]

The first JSON string you listed is an object with an "items" sub array. So you could write jsobj["items"][0] to access the first object in that array (if there is at least 1 object).

The second JSON string you posted is not an array wrapped in an object, it is just an array.

You probably want to deserialize into a strongly typed object instead of a dynamic. Using a dynamic is lazier since it doesn't verify that the JSON is in the format you expect. If your JSON is in the wrong format you want to get an error during the deserialization, not at some point later.

Therefore I would create an object like the following:

public class SomeResult
{
    public int total_count { get; set; }
    public List<SomeItem> items { get; set; }
}

public class SomeItem
{
    public int total_count { get; set; }
    public DateTime created_at { get; set; }
    ...
}

Then you can write:

SomeResult result = serializer.Deserialize<SomeResult>(response.Content);

And now you have a strongly typed class where you can access all of the results.

Just keep in mind that the names need to make exactly and the types you use must match the deserialized type value. For example, if a DateTime has the possibility of being null you must use a nullable DateTime (DateTime?) instead.

Upvotes: 1

Related Questions