Working with JSON web services in Silverlight and Windows Phone 7
July 23, 2012 8 Comments
In this post I’ll explain how to retrieve and display data from JSON web services.
As an example I’ll use the REST service from geonames.org.
JSON response of the example looks so:

At first, you should create C# classes (models) which can be mapped to JSON entities.
The first curly braсe indicates that it is an object, and it has 1 property `geonames`. After this property you can see the square bracket indicating an array. This array consists of many objects, and each object has 12 properties.
So we should create a model for the root object, which looks so:
// { geonames: [{}, {}, {}] }
[DataContract]
public class CitiesList
{
[DataMember(Name = "geonames")]
public List<City> Cities { get; set; }
}
It is important to add DataContract and DataMember attributes to the class and all its properties. Also you should specify the name of the corresponding JSON property (geonames) inside the DataMember attribute.
Then we should create the model for inner objects (cities). As you already saw, each JSON object has 12 properties, but we don’t need all of them. So we can specify only those proeprties which we need, and .Net deserializer will ignore all other properties.
// { name: "", countrycode: "", population: -1 }
[DataContract]
public class City
{
[DataMember(Name = "name")]
public string Name { get; set; }
[DataMember(Name = "countrycode")]
public string CountryCode { get; set; }
[DataMember(Name = "population")]
public int Population { get; set; }
}
So now all that you need is to create an instance of the HttpWebRequest class, get the response and deserialize it by using the DataContractJsonSerializer class. The deserializer requires the System.Servicemodel.Web and System.Runtime.Serialization references.
You must use the two following methods to perform loading and parsing of JSON.
private void BeginDownloadCitiesRequest()
{
// create the http request
HttpWebRequest httpWebRequest = WebRequest.CreateHttp("http://api.geonames.org/citiesJSON?north=44.1&south=-9.9&east=-22.4&west=55.2&lang=en&username=vortexwolf");
httpWebRequest.Method = "GET";
httpWebRequest.Accept = "application/json";
// get the response asynchronously
httpWebRequest.BeginGetResponse(OnGetResponseCompleted, httpWebRequest);
}
private void OnGetResponseCompleted(IAsyncResult ar)
{
var httpWebRequest = (HttpWebRequest)ar.AsyncState;
// get the response
var response = httpWebRequest.EndGetResponse(ar);
// deserialize json
var jsonSerializer = new DataContractJsonSerializer(typeof(CitiesList));
var responseObject = (CitiesList)jsonSerializer.ReadObject(response.GetResponseStream());
// display on the view
Deployment.Current.Dispatcher.BeginInvoke(() => OnCitiesDownloaded(responseObject));
}
The code of creating a http request and getting a response will often repeat in different places of the application, so it is preferrable to move this code to a separate class.
I did it so:
public class HttpGetTask<T>
{
public HttpGetTask(string url, Action<T> onPostExecute)
{
this.Url = url;
this.OnPostExecute = onPostExecute;
}
public void Execute()
{
if (this.OnPreExecute != null)
{
this.OnPreExecute();
}
// create the http request
HttpWebRequest httpWebRequest = WebRequest.CreateHttp(this.Url);
httpWebRequest.Method = "GET";
httpWebRequest.Accept = "application/json";
// get the response asynchronously
httpWebRequest.BeginGetResponse(OnGetResponseCompleted, httpWebRequest);
}
private void OnGetResponseCompleted(IAsyncResult ar)
{
var httpWebRequest = (HttpWebRequest)ar.AsyncState;
// get the response
HttpWebResponse response;
try
{
response = (HttpWebResponse)httpWebRequest.EndGetResponse(ar);
}
catch (WebException)
{
this.InvokeOnErrorHandler("Unable to connect to the web page.");
return;
}
catch (Exception e)
{
this.InvokeOnErrorHandler(e.Message);
return;
}
if (response.StatusCode != HttpStatusCode.OK)
{
this.InvokeOnErrorHandler((int)response.StatusCode + " " + response.StatusDescription);
return;
}
// response stream
var stream = response.GetResponseStream();
// deserialize json
var jsonSerializer = new DataContractJsonSerializer(typeof(T));
var responseObject = (T)jsonSerializer.ReadObject(stream);
// call the virtual method
this.InvokeInUiThread(() => this.OnPostExecute(responseObject));
}
private void InvokeOnErrorHandler(string message)
{
if (this.OnError != null)
{
this.InvokeInUiThread(() => this.OnError(message));
}
}
private void InvokeInUiThread(Action action)
{
Deployment.Current.Dispatcher.BeginInvoke(action);
}
public string Url { get; private set; }
public Action<T> OnPostExecute { get; private set; }
public Action OnPreExecute { get; set; }
public Action<string> OnError { get; set; }
}
You can execute this task by specifying Url and the OnPostExecute callback. Also you can set other properties. Example:
public class MainViewModel : INotifyPropertyChanged
{
public MainViewModel()
{
Cities = new ObservableCollection<CityViewModel>();
string url = "http://api.geonames.orgzz/citiesJSON?north=44.1&south=-9.9&east=-22.4&west=55.2&lang=en&username=vortexwolf";
var task = new HttpGetTask<CitiesList>(url, this.OnPostExecute);
task.OnPreExecute = this.OnPreExecute;
task.OnError = this.OnError;
task.Execute();
}
private void OnPreExecute()
{
this.IsLoading = true;
}
private void OnPostExecute(CitiesList responseObject)
{
this.OnCitiesDownloaded(responseObject);
this.IsLoading = false;
}
private void OnError(string message)
{
MessageBox.Show(message);
this.IsLoading = false;
}
public ObservableCollection<CityViewModel> Cities { get; set; }
private bool _isLoading;
public bool IsLoading
{
get { return _isLoading; }
set
{
_isLoading = value;
RaisePropertyChanged("IsLoading");
}
}
private void OnCitiesDownloaded(CitiesList citiesList)
{
var cityModels = citiesList.Cities
.Select(c =>
new CityViewModel
{
Name = c.Name,
CountryCode = c.CountryCode,
Population = c.Population
})
.ToList();
cityModels.ForEach(this.Cities.Add);
}
public event PropertyChangedEventHandler PropertyChanged = delegate { };
public void RaisePropertyChanged(string propertyName)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
I created the sample application for Windows Phone 7 which retrieves JSON data and displays it on the phone.

The source code of the example you can download here: https://dl.dropbox.com/u/8047386/WordPress/PhoneJsonTest.zip
{“total”:47,”movies”:[{"id":"771242005","title":"Magic Mike","year":2012,"mpaa_rating":"R","runtime":110,"critics_consensus":"Magic Mike's sensitive direction, smart screenplay, and strong performances allows audiences to have their beefcake and eat it too.","release_dates":{"theater":"2012-06-29","dvd":"2012-10-23"},"ratings":{"critics_rating":"Certified Fresh","critics_score":79,"audience_rating":"Upright","audience_score":63},"synopsis":"Set in the world of male strippers, Magic Mike is directed by Steven Soderbergh and stars Channing Tatum in a story inspired by his real life. The film follows Mike (Tatum) as he takes a young dancer called The Kid (Pettyfer) under his wing and schools him in the fine arts of partying, picking up women, and making easy money. -- (C) Warner Bros.","posters":{"thumbnail":"http://content8.flixster.com/movie/11/16/66/11166610_mob.jpg","profile":"http://content8.flixster.com/movie/11/16/66/11166610_pro.jpg","detailed":"http://content8.flixster.com/movie/11/16/66/11166610_det.jpg","original":"http://content8.flixster.com/movie/11/16/66/11166610_ori.jpg"},"abridged_cast":[{"name":"Channing Tatum","id":"162661835","characters":["Magic Mike"]},{“name”:”Alex Pettyfer”,”id”:”326298019″,”characters”:["Adam","The Kid"]},{“name”:”Matt Bomer”,”id”:”771077752″,”characters”:["Ken"]},{“name”:”Joe Manganiello”,”id”:”770800475″,”characters”:["Big Dick Richie"]},{“name”:”Matthew McConaughey”,”id”:”162652350″,”characters”:["Dallas"]}],”alternate_ids”:{“imdb”:”1915581″},”links”:{“self”:”http://api.rottentomatoes.com/api/public/v1.0/movies/771242005.json”,”alternate”:”http://www.rottentomatoes.com/m/magic_mike/”,”cast”:”http://api.rottentomatoes.com/api/public/v1.0/movies/771242005/cast.json”,”clips”:”http://api.rottentomatoes.com/api/public/v1.0/movies/771242005/clips.json”,”reviews”:”http://api.rottentomatoes.com/api/public/v1.0/movies/771242005/reviews.json”,”similar”:”http://api.rottentomatoes.com/api/public/v1.0/movies/771242005/similar.json”}}],”links”:{“self”:”http://api.rottentomatoes.com/api/public/v1.0/lists/dvds/upcoming.json?page_limit=1&country=us&page=1″,”next”:”http://api.rottentomatoes.com/api/public/v1.0/lists/dvds/upcoming.json?page_limit=1&country=us&page=2″,”alternate”:”http://www.rottentomatoes.com/dvd/upcoming.json”},”link_template”:”http://api.rottentomatoes.com/api/public/v1.0/lists/dvds/upcoming.json?page_limit={results-per-page}&page={page-number}&country={country-code}”}
My jason looks like this.but i want only movie name and release date.should i create a class that has all these
You need 3 classes:
1. class MoviesListModel, 1 property Movies
2. class MovieItemModel, 2 properties, Title and ReleaseDates
3. Class ReleaseDatesModel, 2 properties, Theater and Dvd
The main problem is with the ReleaseDates property. It must be a class, which is quite complicated.
the source code is unavailable…can u give a working link for it
Actually the dropbox link works, just checked it myself.
Anyway I uploaded it here as well: http://rghost.net/41933135
http://json2csharp.com/
It is quite a good autogenerator for complex classes. Though some people wouldn’t like properties which start from a lowercase letter.
Pingback: Displaying progress bar while loading JSON from Web Services for Windows Phone 7 « Silverlight, WPF and Windows 8 Development
Can I extract obtained data from citiesList to multiple purpose?
For example if in each citiesList has image, and I want to display those image in panoramaItem, what should I do?