Click here to Skip to main content
15,867,453 members
Articles / Web Development

Consuming a Json WebService from a C# or VB Application

Rate me:
Please Sign up or sign in to vote.
4.81/5 (26 votes)
2 Apr 2012CPOL7 min read 332.9K   23.7K   94   24
Some steps for consuming a Json web service from a C# application

Introduction

Json has become a widespread data format in web applications, mainly with Ajax enriched web sites. Also "normal" Windows applications can communicate with such web services and consume Json data. I’ll show here a way to accomplish that, and some caveats.

Background 

A short time ago, I started to learn how to use ReSTful we services. Some good examples on writing such services are available from "REST in Windows Communication Foundation (WCF)"(^). But I also wanted to consume the service from a C# application. After a lot of trial and error, I decided to find out how to consume an existing web service first. As an example, I chose the Panoramio data API, described at http://www.panoramio.com/api/data/api.html (^).

Naïve Approach 

Visual Studio allows us to add a reference to a web service. Hence I clicked "Add Service Reference", entered the address http://www.panoramio.com/map/get_panoramas.php, and clicked "Go". After a while, I received the message: "An error occurred (details) while attempting to find services at..." The details were: "… The remote server returned an unexpected response: (412) Precondition failed. …"

I checked with a web browser if I could get some meta-information from the server by adding a "?wsdl" to above address, as I would do with a "normal" web service. The response was: "Bad Request".

After a lot of research on Google, it turns out that the discovery using Web Services Description Language (^) is not common with ReSTful services. And alternatives are not yet available, only being discussed.

Step by Step

What to do now after that failure? Well, we can break the task down to the following steps:

  • Set up the URL with all parameters
  • Send a GET WebRequest
  • Receive the Json formatted data
  • Deserialize the object(s)
  • Do something useful with the received data

Most of these steps do not cause any problems, it should look something like:

C#
string url = …;
WebRequest request = WebRequest.Create(url);
WebResponse ws = request.GetResponse();
JsonSerializer jsonSerializer = new JsonSerializer(typeof(PanoramioData));
PanoramioData photos = (PanoramioData)jsonSerializer.Deserialze(ws.GetResponseStream());

But where do we find that Serializer? And how to define the classes ("PanoramioData") for those objects?

Panoramio shows an excerpt of a sample response, but no definition of the data – we have to guess their types from the values we see. If we want to use a service where even a sample response is not shown, we can still enter the URL in a web browser, and save the response to a text file.

I did not read through the definitions of the Json format (see http://www.json.org/ (^)), it looked so easy to understand, and quickly wrote two classes: "public class PanoramioData" for the root element, and "public class Photo" for the collection of photos.

Now we need a (de-)serializer. With XML, the "XmlSerializer" can be found in the "System.Xml.Serialization" namespace. But there is no "System.Json" namespace… The serializer we need here is called "DataContractJsonSerializer" and resides in the "System.Runtime.Serialization.Json" namespace. Though the constructor looks still common (we pass the type of the object to be deserialized), there is no "Deserialize()" method. Instead, we must call "ReadObject()". The resulting object is cast to our required type, and we can use it.

I tried that and caught an exception… What had happened? The "upload_date" property is not a "DateTime" – it is a string! According to "An Introduction to JavaScript Object Notation (JSON) in JavaScript and .NET" (^), there is no real standard for formatting a DateTime with Json, and the way Panoramio chose is not understood by the DataContractJsonSerializer.

After that little change, the application really works! If we needed that property in the appropriate type, we would have to add an extra function (e.g. public DateTime GetUploadDate()) which parses the string.

The main lines of code are now:

C#
string url = …;
WebRequest request = WebRequest.Create(url);
WebResponse ws = request.GetResponse();
DataContractJsonSerializer jsonSerializer = 
		new DataContractJsonSerializer(typeof(PanoramioData));
PanoramioData photos = (PanoramioData)jsonSerializer.ReadObject(ws.GetResponseStream());

which could actually be put into a static method of the PanoramioData class (i.e. public static PanoramioData FromURL(string url)).

Alternative Serializer: JavaScriptSerializer

In the System.Web.Script.Serialization namespace, there is another Serializer: JavaScriptSerializer. We must add a reference to System.Web.Extensions.dll before we can use it. Again, usage is different:

It is instantiated with a parameterless constructor. The Deserialize method requires a string, i.e. the web response must be read into a StreamReader and from there into a string.

This serializer recognizes the Date format used by Panoramio. But it does not use a [DataMember(Name="OtherName")] attribute.

Class Generation Tools

Is that manual generation of the classes really the only option we have? Is there no such thing like the xsd tool for XML data with Json?

I found two very nice tools for creating classes from Json serialized data:

JSON C# Class Generator

This tool generates C# classes from a Json formatted string. A helper class for deserialization is also created. The deserialization process is different from the processes described above.

Source code and binary release of the tool are available at http://jsonclassgenerator.codeplex.com/ (^).

json2csharp

This is a beautiful web site: http://json2csharp.com/ (^). Enter your Json string – or even only the URL from where you received the Json data, and the tool generates the classes which are then used as described above.

Class Generator for VB.Net

I did not find such a tool on the web. For the sample project, I manually translated the C# code to VB.

Exception Handling

With ReSTful Web services, an exception should result in an http status code in the range of 400-499. The message body should then contain some more information on the exception.

With the Panoramio data API used in this example, the status code of 400 corresponds to this idea, but the message body is a full (html) web page instead of a Json formatted response. The citiesJson request of geonames (^) still returns status code 200 (=OK) in case of errors, but a Json formatted error message.

request.GetResponse() throws a WebException for a status code of 400. This means that we have to catch the WebException, then we can access its WebResponse property, and get further information from it.

When the serializer (no matter if JavaScriptSerializer or DataContractJsonSerializer) is used for deserializing the object returned from the geonames API and there was an exception, it still returns a "valid" root object, only all its members being null. Hence we have to check for that case, then try to deserialize the message to an exception status message.

Example Project

The example project contains the classes for the Panoramio data API and the geonames API, and a simple interface for setting the parameters. These parameters are not checked for usefulness and format, they are directly put into the URL – it is up to you to enter useful data.

On a second form, the results are shown: the photos are placed into PictureBoxes (upon a double click the picture is opened in the default web browser), below the picture is a LinkLabel to the author's page. Moving the mouse over a picture shows the photo title.

With the buttons "Place" and "Toponym", you can search for the nearest place or toponym nearby, if you have a valid user name for the geonames API.

The code shows the use of both serializers and their respective error handling.

Conclusion

Though consuming a ReSTful Json web service involves many more manual steps than "common" aspx web services, it is actually not really complicated (only terribly cumbersome) when you follow the steps above and use the tools. 

The lack of a discovery method – and tools using it automatically – makes ReSTful services a bad choice for consumption. The methods for exception handling make it even worse.

And now try to find out how to do more complicated things like updating data on the server – the most important point in a real world application, but not available on publicly accessible web servers…

How nice would be a good toolset and some more standardization!

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
Germany Germany
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
Questionaccessing /parsing JSON API in VS2008 Pin
Member 42542621-Mar-16 11:06
Member 42542621-Mar-16 11:06 
AnswerRe: accessing /parsing JSON API in VS2008 Pin
Bernhard Hiller1-Mar-16 21:35
Bernhard Hiller1-Mar-16 21:35 
Generalgreat article Pin
sivasree.b1-Jan-14 22:13
sivasree.b1-Jan-14 22:13 
GeneralRe: great article Pin
Bernhard Hiller2-Jan-14 0:19
Bernhard Hiller2-Jan-14 0:19 
Generalvery good Pin
Bhushan Gupta31-Dec-13 19:10
Bhushan Gupta31-Dec-13 19:10 
GeneralExcellent Article. Pin
abhi_here23-Oct-13 10:38
abhi_here23-Oct-13 10:38 
GeneralRe: Excellent Article. Pin
Bernhard Hiller23-Oct-13 20:02
Bernhard Hiller23-Oct-13 20:02 
QuestionExcellent ,But How to consume class which is declared at service using Jdon through uri Pin
kingsa4-Oct-13 23:22
kingsa4-Oct-13 23:22 
AnswerRe: Excellent ,But How to consume class which is declared at service using Jdon through uri Pin
Bernhard Hiller6-Oct-13 20:55
Bernhard Hiller6-Oct-13 20:55 
GeneralMy vote of 5 Pin
Neopandit14-Jun-13 10:01
Neopandit14-Jun-13 10:01 
GeneralRe: My vote of 5 Pin
Bernhard Hiller16-Jun-13 20:11
Bernhard Hiller16-Jun-13 20:11 
QuestionBasics please.... Pin
J.C. Martin21-Mar-13 7:39
J.C. Martin21-Mar-13 7:39 
NewsThanks Pin
karenpayne12-Dec-12 10:14
karenpayne12-Dec-12 10:14 
GeneralMy vote of 5 Pin
Giovanni Pulvirenti2-Dec-12 3:50
Giovanni Pulvirenti2-Dec-12 3:50 
QuestionExcellent: 5 Pin
harveyt1-Dec-12 8:05
harveyt1-Dec-12 8:05 
GeneralMy vote of 5 Pin
harveyt1-Dec-12 7:50
harveyt1-Dec-12 7:50 
QuestionHow to keep the object model in sync Pin
Mike Lacy2-Mar-12 2:18
Mike Lacy2-Mar-12 2:18 
AnswerRe: How to keep the object model in sync Pin
K Quinn2-Apr-12 5:41
K Quinn2-Apr-12 5:41 
GeneralMy vote of 5 Pin
Leonardo Paneque24-Feb-12 16:26
Leonardo Paneque24-Feb-12 16:26 
GeneralMy vote of 5 Pin
Manoj Kumar Choubey16-Feb-12 1:44
professionalManoj Kumar Choubey16-Feb-12 1:44 
QuestionWhat about POST Pin
Sergii Lavrinenko3-Aug-11 1:04
Sergii Lavrinenko3-Aug-11 1:04 
AnswerRe: What about POST Pin
Bernhard Hiller3-Aug-11 3:30
Bernhard Hiller3-Aug-11 3:30 
GeneralJSON library Pin
YevgeniyZ2-Aug-11 0:35
YevgeniyZ2-Aug-11 0:35 
GeneralRe: JSON library Pin
Bernhard Hiller3-Aug-11 3:24
Bernhard Hiller3-Aug-11 3:24 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.