In this post we will take a look at how to call a web service from a Windows Phone 8 app and retrieve data in JSON format. We will be calling a simple REST web service from our sample application to retrieve the latest weather information and display the same.
Web Service
We will be using the weather API provided by OpenWeatherMap.org. The Api is simple and free to use and provides current weather information as well as weather forecast from the next few days. The api provides various options to get the weather information based on Location, Pin Code, Latitude/Longitude coordinated etc. We will be using the below mentioned api call to get the weather forecast data for a week based on Pin Code.
“http://api.openweathermap.org/data/2.5/forecast/daily?q=London&mode=json&units=metric&cnt=7” . As you can see, this query gets the weather data for ‘London’ in JSON format. We can also pass the Pincode to the same query instead of City Name. We are also specifying the ‘mode’ as JSON as we want the data to be returned in JSON format. If you enter the above URL in Firefox/IE, you will get the data in JSON format as shown below.
This contains all the data we need and we will be using the same in our app.
Creating the Project
Open Visual Studio 2013 –> New Project –> Windows Phone Apps –> Blank App. In the Application Name enter “WebServiceExampleApp” and click “Ok”. This will create a new Windows phone application with the default template.
We will also be using the “JSON.Net” and “Microsoft Http Client Libraries” Nuget packages in our app. Right Click on the solution and select “Manage NuGet packages” to open Nuget package manager. Search and install these two packages as shown below in your project. The Json.net is a powerful JSON serializer which provides classes for serializing/deserializing json.
In our application, we will allow the user to enter the Pincode and hit the button the fetch the latest weather data for that Pincode. Our final UI will look as shown below.
Shown Below is the XAML that we have used.
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"> <StackPanel> <StackPanel> <TextBlock>Enter PinCode</TextBlock> <TextBox Name="txtPincode"></TextBox> <Button Name="btnGetData" Content="Get Data" Click="btnGetData_Click" /> </StackPanel> <ProgressBar IsIndeterminate="true" Visibility="Collapsed" Name="pbWeather" /> <StackPanel Name="spWeatherInfo"> <StackPanel Orientation="Horizontal"> <TextBlock Margin="4" Name="txtCity" Text="{Binding city.name }" Style="{StaticResource PhoneTextNormalStyle}"/> <TextBlock Margin="4" Text="{Binding city.country}" Style="{StaticResource PhoneTextNormalStyle}" /> </StackPanel> <StackPanel> <ListBox ItemsSource="{Binding list}"> <ListBox.ItemTemplate> <DataTemplate> <StackPanel Margin="8" > <StackPanel Orientation="Horizontal" Margin="2"> <TextBlock Style="{StaticResource PhoneTextNormalStyle}" Text="{Binding Path=dt, Converter={StaticResource DateConverter}}" Margin="2" /> <TextBlock Style="{StaticResource PhoneTextNormalStyle}" Text="{Binding weather[0].description}" Margin="2" /> </StackPanel> <StackPanel Orientation="Horizontal" Margin="2"> <TextBlock Margin="2">Min Temp</TextBlock> <TextBlock Margin="2" Text="{Binding temp.min}" /> <TextBlock Margin="2">Max Temp</TextBlock> <TextBlock Margin="2" Text="{Binding temp.max}" /> </StackPanel> </StackPanel> </DataTemplate> </ListBox.ItemTemplate> </ListBox> </StackPanel> </StackPanel> </StackPanel> </Grid>
The stack panel “spWeatherInfo” is used to display the data retrieved from the service. We are using a ListBox with a Data Template to display the weather information using DataBinding.
In the JSON received from the service, we are getting the “date” in Unix style format so we are making use of a value converter class to convert it into a DateTime object for display. Add a new class called “DateConverter.cs” in the application the code of which is shown below.
public class DateConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { var epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); return epoch.AddSeconds((int)value).ToShortDateString(); } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } }
It derives from the “IValueConverter” interface and implements the Convert() method which is used to convert the data from int to a DateTime. It also has a ConvertBack method which we have not implemented as we have not used it.
We have defined the converter in our MainPage.xaml above the Grid tag.
<phone:PhoneApplicationPage.Resources > <converter:DateConverter xmlns:converter="clr-namespace:WebServiceExampleApp" x:Key="DateConverter"></converter:DateConverter> </phone:PhoneApplicationPage.Resources>
We then apply the Converter to the TextBlock as shown below
<TextBlock Style="{StaticResource PhoneTextNormalStyle}" Text="{Binding Path=dt, Converter={StaticResource DateConverter}}" Margin="2">Date</TextBlock>
The converter will convert the date from “int” to DateTime before displaying it in the TextBlock.
Our JSON contains the information in a lot of complex objects. We will need to convert it into a list of objects that we can use with our application. I have used a online tool called Json2Csharp which generated C# classes from JSON. Add a new class to the application called WeatherObject having below code which has been generated using the tool.
namespace WebServiceExampleApp { public class Coord { public double lon { get; set; } public double lat { get; set; } } public class City { public string id { get; set; } public string name { get; set; } public Coord coord { get; set; } public string country { get; set; } public int population { get; set; } } public class Temp { public double day { get; set; } public double min { get; set; } public double max { get; set; } public double night { get; set; } public double eve { get; set; } public double morn { get; set; } } public class Weather { public int id { get; set; } public string main { get; set; } public string description { get; set; } public string icon { get; set; } } public class List { public int dt { get; set; } public Temp temp { get; set; } public double pressure { get; set; } public int humidity { get; set; } public List<Weather> weather { get; set; } public double speed { get; set; } public int deg { get; set; } public int clouds { get; set; } public double? rain { get; set; } } public class WeatherObject { public string cod { get; set; } public double message { get; set; } public City city { get; set; } public int cnt { get; set; } public List<List> list { get; set; } } }
We do our web service call and data retrieval on click of GetData button. In the MainPage.xaml.cs, include the following namespaces.
using System.Net.Http; using System.Net.Http.Headers; using Newtonsoft.Json;
Our GetData button click method is implemented as shown below
private async void btnGetData_Click(object sender, RoutedEventArgs e) { try { using (HttpClient client = new HttpClient()) { pbWeather.Visibility = System.Windows.Visibility.Visible; client.BaseAddress = new Uri("http://api.openweathermap.org"); var url = "data/2.5/forecast/daily?q={0}&mode=json&units=metric&cnt=7"; client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); HttpResponseMessage response = await client.GetAsync(String.Format(url, txtPincode.Text)); if (response.IsSuccessStatusCode) { var data = response.Content.ReadAsStringAsync(); var weatherdata = JsonConvert.DeserializeObject<WeatherObject>(data.Result.ToString()); spWeatherInfo.DataContext = weatherdata; } pbWeather.Visibility = System.Windows.Visibility.Collapsed; } } catch(Exception ex) { MessageBox.Show("Some Error Occured"); pbWeather.Visibility = System.Windows.Visibility.Collapsed; } }
We are creating an object of the HttpClient class which will be used to call the web service. We are also specifying the base address of the service and we are construction the url dynamically based on the PinCode which the user has provided. The “client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(“application/json”));” sets the request header to accept data in JSON format.
We then call the “GetAsync()” function passing the URL of the web service. We then check the response to see if that was successful or not. If the response was “Ok”, we read the JSON as a string by calling the “ReadAsStringAsync()” method of response object. Once that is done, we deserialize the JSON object and convert it into appropriate class which is then used to set the DataContext of stack panel.
Once DataBinding is complete, you will be able to see the data as shown below.
I have used a simple example to demonstrate how to call the web service from Windows Phone. In a real world scenario, you will need to check for a lot of error or exception conditions also.