0

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\": \"cutesycanvas@gmail.com\"}, {\"unique\": {\"link\": 1}, \"total\": 22, \"recipient\": \"angelina40d@hotmail.com\"}]"
Ry-
  • 218,210
  • 55
  • 464
  • 476
Alma
  • 3,780
  • 11
  • 42
  • 78
  • If your JSON parser can’t handle whitespace, you might need a new JSON parser. Anyways, you say there’s an error – what is it? – Ry- Nov 04 '13 at 18:40
  • the error is The best overloaded method match for 'System.Collections.Generic.Dictionary.this[string]' has some invalid arguments, that it is beacuse it cannot find the feild. – Alma Nov 04 '13 at 18:43

1 Answers1

1

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.

Trevor Elliott
  • 11,292
  • 11
  • 63
  • 102
  • the problem is that when it has \n the JavaScriptSerializer is not working so I can bnot get the value of the json feild in this line: int total_count= Convert.ToInt32(jsobj[0]["total_count"]); – Alma Nov 04 '13 at 18:41
  • So how access to this: { "items": [ { "total_count": 678, – Alma Nov 04 '13 at 18:51
  • when I use: string daily = jsobj["items"]["0"]; it gave me error, cannot inplicitly convert string to int and when I convert to int, it gave me an error that cannot implicitly convert int to string. – Alma Nov 04 '13 at 18:56
  • @nikoom See my edit for a better way to do this. And you are getting that error because you are retrieving "total_count" which is certainly an integer and you're trying to store it in a string variable. You can't store an integer value in a string. You must use a convert function such as `ToString()` etc. – Trevor Elliott Nov 04 '13 at 19:04
  • Thanks, it worked perfect, the only problem that I have now is of name of Json item is event, so I cannot use it is properties as it is a reserve work and gave me an error, what should I do? – Alma Nov 04 '13 at 21:07
  • @nikoom See [this question](http://stackoverflow.com/questions/1100191/javascriptserializer-deserialize-how-to-change-field-names). You can use attributes to specify a different JSON name as the C# name. – Trevor Elliott Nov 04 '13 at 21:11
  • I found it, I used @event and it works, @ Trevor Elliott thanks for your help. – Alma Nov 04 '13 at 22:24