I’ve long advocated using JSON when building mobile and cloud applications. If nothing else, the payload size makes it extremely efficient when transferred over the wire – take a look at the size of the same information formatted as OData, REST-XML, and lastly JSON:

JSON versus OData versus REST-XML

Pretty compelling.

Despite the use of JSON – and great frameworks like JSON.NET and SimpleJson – I always struggled with creating my C# classes when working with an existing web service that returned JSON. It can take a long time to create these C# classes correctly, and often time I’d take a lazy approach and either use the JObject or an IDictionary such that I didn’t have to have a C# class – something like:

var json = (IDictionary<string, object>)SimpleJson.DeserializeObject(data);

Yesterday I stumbled upon a tool that makes this SO amazingly easy. In many ways I’m bothered by the fact that it’s taken me so long to find it – has this been one of the best kept secrets on the Internet or did I just miss it?

http://json2csharp.com/

This website is as simple as it is powerful. Simply paste your JSON into the textbox, click Generate, and voilà you have C# objects!

Take a look. Here’s some JSON returned back from the Untappd API:

{
  "meta": {
    "code": 200,
    "response_time": {
      "time": 0.109,
      "measure": "seconds"
    }
  },
  "notifications": [],
  "response": {
    "pagination": {
      "next_url": "http://api.untappd.com/v4/thepub?max_id=11697698",
      "max_id": 11697698,
      "since_url": "http://api.untappd.com/v4/thepub?min_id=11697724"
    },
    "checkins": {
      "count": 2,
      "items": [
        {
          "checkin_id": 11697724,
          "created_at": "Wed, 22 Aug 2012 12:56:41 +0000",
          "checkin_comment": "",
          "user": {
            "uid": 205218,
            "user_name": "asiahobo",
            "first_name": "Bum",
            "last_name": "",
            "location": "",
            "url": "0",
            "relationship": null,
            "bio": "0",
            "user_avatar": "https://untappd.s3.amazonaws.com/profile/7d21ba831edb33341b98f86e09795ed7_thumb.jpg",
            "contact": {
              "twitter": "asiahobo",
              "foursquare": 31652652
            }
          },
          "beer": {
            "bid": 9652,
            "beer_name": "Maredsous 8° Brune",
            "beer_label": "https://untappd.s3.amazonaws.com/site/beer_logos/beer-maredsous.jpg",
            "beer_style": "Belgian Dubbel",
            "auth_rating": 0,
            "wish_list": false
          },
          "brewery": {
            "brewery_id": 6,
            "brewery_name": "Abbaye de Maredsous (Duvel Moortgat)",
            "brewery_label": "https://untappd.s3.amazonaws.com/site/brewery_logos/brewery-AbbayedeMaredsousDuvelMoortgat_6.jpeg",
            "country_name": "Belgium",
            "contact": {
              "twitter": "",
              "facebook": "www.facebook.com/pages/Abbaye-De-Maredsous/208016262548587fine",
              "url": "www.maredsous.be/"
            },
            "location": {
              "brewery_city": "",
              "brewery_state": "Denée",
              "lat": 50.3044,
              "lng": 4.77149
            }
          },
          "venue": [],
          "comments": {
            "count": 0,
            "items": []
          },
          "toasts": {
            "count": 0,
            "auth_toast": null,
            "items": []
          },
          "media": {
            "count": 0,
            "items": []
          }
        },
        {
          "checkin_id": 11697723,
          "created_at": "Wed, 22 Aug 2012 12:56:35 +0000",
          "checkin_comment": "",
          "user": {
            "uid": 137722,
            "user_name": "Mjoepp",
            "first_name": "Christoffer",
            "last_name": "",
            "location": "Linköping",
            "url": "",
            "relationship": null,
            "bio": "",
            "user_avatar": "http://gravatar.com/avatar/f1672535a7caa3bd686267257d33c588?size=100&d=https%3A%2F%2Funtappd.s3.amazonaws.com%2Fsite%2Fassets%2Fimages%2Fdefault_avatar.jpg",
            "contact": {
              "foursquare": 25958771
            }
          },
          "beer": {
            "bid": 12145,
            "beer_name": "Chocolate",
            "beer_label": "https://untappd.s3.amazonaws.com/site/beer_logos/beer-ChocolatePorter_12145.jpeg",
            "beer_style": "English Porter",
            "auth_rating": 0,
            "wish_list": false
          },
          "brewery": {
            "brewery_id": 844,
            "brewery_name": "Meantime Brewing Company",
            "brewery_label": "https://untappd.s3.amazonaws.com/site/brewery_logos/brewery-MeantimeBrewingCompanyLimited_844.jpeg",
            "country_name": "England",
            "contact": {
              "twitter": "MeantimeBrewing",
              "facebook": "http://www.facebook.com/meantimebrewing",
              "url": "http://www.meantimebrewing.com"
            },
            "location": {
              "brewery_city": "London",
              "brewery_state": "",
              "lat": 51.5081,
              "lng": -0.128005
            }
          },
          "venue": [],
          "comments": {
            "count": 0,
            "items": []
          },
          "toasts": {
            "count": 0,
            "auth_toast": null,
            "items": []
          },
          "media": {
            "count": 0,
            "items": []
          }
        }
      ]
    }
  }
}

I’m sad to admit that, in the past, I’d like create my C# objects by hand and then either conform to the JSON or map between the two. It requires a TON of time and is extremely error prone. With http://json2csharp.com/ all I do is paste this into the textbox and click Generate. I’ll get the following output:

public class ResponseTime
{
    public double time { get; set; }
    public string measure { get; set; }
}

public class Meta
{
    public int code { get; set; }
    public ResponseTime response_time { get; set; }
}

public class Pagination
{
    public string next_url { get; set; }
    public int max_id { get; set; }
    public string since_url { get; set; }
}

public class Contact
{
    public string twitter { get; set; }
    public int foursquare { get; set; }
}

public class User
{
    public int uid { get; set; }
    public string user_name { get; set; }
    public string first_name { get; set; }
    public string last_name { get; set; }
    public string location { get; set; }
    public string url { get; set; }
    public object relationship { get; set; }
    public string bio { get; set; }
    public string user_avatar { get; set; }
    public Contact contact { get; set; }
}

public class Beer
{
    public int bid { get; set; }
    public string beer_name { get; set; }
    public string beer_label { get; set; }
    public string beer_style { get; set; }
    public int auth_rating { get; set; }
    public bool wish_list { get; set; }
}

public class Contact2
{
    public string twitter { get; set; }
    public string facebook { get; set; }
    public string url { get; set; }
}

public class Location
{
    public string brewery_city { get; set; }
    public string brewery_state { get; set; }
    public double lat { get; set; }
    public double lng { get; set; }
}

public class Brewery
{
    public int brewery_id { get; set; }
    public string brewery_name { get; set; }
    public string brewery_label { get; set; }
    public string country_name { get; set; }
    public Contact2 contact { get; set; }
    public Location location { get; set; }
}

public class Comments
{
    public int count { get; set; }
    public List<object> items { get; set; }
}

public class Toasts
{
    public int count { get; set; }
    public object auth_toast { get; set; }
    public List<object> items { get; set; }
}

public class Media
{
    public int count { get; set; }
    public List<object> items { get; set; }
}

public class Item
{
    public int checkin_id { get; set; }
    public string created_at { get; set; }
    public string checkin_comment { get; set; }
    public User user { get; set; }
    public Beer beer { get; set; }
    public Brewery brewery { get; set; }
    public List<object> venue { get; set; }
    public Comments comments { get; set; }
    public Toasts toasts { get; set; }
    public Media media { get; set; }
}

public class Checkins
{
    public int count { get; set; }
    public List<Item> items { get; set; }
}

public class Response
{
    public Pagination pagination { get; set; }
    public Checkins checkins { get; set; }
}

public class RootObject
{
    public Meta meta { get; set; }
    public List<object> notifications { get; set; }
    public Response response { get; set; }
}

Pretty amazing! Now, note that it’s not perfect – there’s both a Contact and Contact2 class, but that’s easy to fix by merging the two and updating references. I’ll gladly perform this little bit of cleanup given the hours this tool just saved me.

Now that I have these classes, it’s really easy to use JSON.NET to load them with data.

RootObject publicFeed = new RootObject();

using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
    data = reader.ReadToEnd();

    publicFeed = JsonConvert.DeserializeObject<RootObject>(data);
}

Now it’s a simple matter of using my RootObject within my applications.

I feel like I may be the last person to have heard of this tool, in which case I’m both embarrassed and bitter – couldn’t you all have told me about this years ago? Smile

I hope this helps!

  • http://ianfelton.com Ian Felton

    @shansleman demo’d this at ‘That Conference’. It is native behavior in Visual Studio 2012.

    • Wade

      I don’t believe it’s native to VS 2012 yet. Today you have to grab Web Essentials 2012.

  • http://activeengine.wordpress.com David Robbins

    Great post – this tool looks promising. I would prefer that the properties be in PascalCase instead of camelCase. Maybe that’s an opportunity for someone from the community to write an add-on :)

  • Pingback: Cheatsheet: 2012 08.17 ~ 08.31 - gOODiDEA.NET

  • Rajeesh

    Hi,

    Its very helpful to manage and use the c# classes using the JOSN.
    Many thanks for this post :)

  • ross

    Seems like a useful utility. I haven’t found it a chore to write such classes by hand, a few hours in the scheme of things, but nice nonetheless.

    I’m not sure I agree with your json vs odata vs rest example. you can do odata and rest using a json wire format. it is really just useful to say that json is a more efficient format/protocol than xml.

    I wonder, is json more or less cpu intensive (ie slower or faster) to deserialize compared with xml? And if it is slower to deserialize / transform / query, I wonder if there are cases where you might be better with xml?

  • http://profile.yahoo.com/LRKTUDBTAZK25LMWRCLNX3OIIM Aravind Rajagopal K

    Great post Wade..