Connecting Windows Phone 7 with ASP.NET Web Pages

In this tutorial you will learn how ASP.NET Web Pages with Razor syntax can be used to build a RESTful web service that is capable of delivering weather forecast data to a Windows Phone 7 application. We will be using WebMatrix, a lightweight tool for web development to write code and manage the website throughout this tutorial.

Getting Started

The Current Weather Site

The REST service that you will create will be built on top of the Current Weather WebMatrix site that was built in the tutorial Consuming and Storing Data from a REST service with Razor. In that tutorial we learned how the integrated database features of WebMatrix could be used to retrieve and cache weather service data. Some of the code you will be looking at in this tutorial will directly reference the weather forecast features developed for the Current Weather site, so if you would like to familiarize yourself with how the site works, feel free to review that tutorial before continuing.

What You’ll Need

In addition to WebMatrix and the Razor syntax, you will be working with some standard web technologies in this tutorial. If you have a basic understanding of JSON, XAML and C# you should be set.

A RESTful Service

The first thing we will want to do is review the Razor methods that the Current Weather site uses to retrieve forecast data. The functions we want to use are located in a Razor function block in the App_Code folder of the site. Function blocks are called using the following signature:

FileName.FunctionName([DataType arg], [DataType arg]…);

The filename that the Current Weather site uses is Weather.cshtml and the function is GetForecastByZipcode(string zip). So to call this function using Razor you would write:

@{
   var temp = Weather.GetForecastByZipcode("92805");
}

As you can see, we simply pass any valid zip code to the function in order to receive the forecast data for that area. The object that is returned is a simple container that holds the temperature data that is retrieved from a remote weather service.

public class Temperature
{

   public string Zip { get; set; }
   public string Latitude { get; set; }
   public string Longitude { get; set; }
   public int MaxTemp { get; set; }
   public int MinTemp { get; set; }
   public string Forecast { get; set; }

}

Each property of the Temperature object can be easily accessed through the ‘temp’ variable. For example, the following Razor code will write the forecast description into an HTML paragraph:

<p>@temp.Forecast</p>

So now that now you understand how weather forecast data is accessed, let’s take a look at how the data stored in the Temperature object can be converted to a format that is suitable for use by a Windows Phone 7 application.

What is REST

A RESTful web service is simply a service that is implemented using HTTP as a protocol. That means that requests are made from client to server using a valid URI as a locator. A typical RESTful API will respond to requests with a standards compliant data format like JSON or XML. For this tutorial you will be creating a very simple service layer on top of the GetForecastByZipcode method that we discussed in the last section.

Using Razor to Deliver RESTful Content

In order to create a RESTful web service layer on top of the Current Weather site, we will need to add some code that accepts a client supplied zip code and returns data in a standardized format. So let’s start by creating an empty Razor page to hold the required code. For this tutorial we are using a page called JsonService.cshtml, but you are free to name it anything you like. This page will only contain a small Razor code block, so any default HTML can safely be removed.

Now that we have a place to hold the service code, let’s discuss how we can add support for accepting zip codes. Since a RESTful web service is implemented over HTTP, the simplest means of passing HTTP compliant data into a URL is with query string parameters. So let’s add a code block the page and extract a query parameter from the Request object called ‘zip’.

@{
   var zip = Request.QueryString["zip"];
}

Now whenever a request is made to the following URL:

http://localhost/CurrentWeather/JsonService.cshtml?zip=92805

The Razor variable, zip, will contain the requested zip code. You will also probably want to make sure that if the zip parameter is missing that the page handles it appropriately. So let’s add a little more code to make sure that the request is properly formatted.

@{
   var zip = Request.QueryString["zip"];

   if(zip == null){
      Response.Write("Missing Zip Parameter");
      return;
   }

   if(zip != string.Empty){
   //zip code exists

   }else{
      Response.Write("Invalid Zip Code");
   }
}

If either the zip parameter is missing a value or not even included in the URL, the client that issued the request will receive a simple message indicating what went wrong.

Alright, so now that we have a zip code supplied by a client request, we can retrieve the weather forecast data using the same function call to GetForecastByZipcode we looked at earlier. However we still need a convert the data held in the Temperature object to a format that any client can consume. To do this we will be using the JavaScript Object Notation (JSON) protocol. JSON is a text-based open standard that has become the leading interchange format for sharing data in a web environment. The JSON standard uses a concise key/value pair format that is perfect for parsing data into a readable format. Although the JSON specification is well documented, the code required to convert a Razor object into JSON would be pretty lengthy to write yourself. Thankfully, the WebMatrix environment comes preinstalled with a JSON Helper that simplifies the process of encoding and decoding objects into a few simple functions.

Let’s take look at how the WebMatrix Json Helper can be used to encode and decode the Temperature object returned by the GetForecastByZipcode function by adding some test output to the service page.

if(zip != string.Empty){
//zip code exists
   var temp = Weather.GetForecastByZipcode("92805");
   Response.Write("<p>" + temp.Forecast + "</p>");
   var json = Json.Encode(temp);
   Response.Write("<p>" + json + "</p>");
   var temp2 = Json.Decode(json);
   Response.Write("<p>" + temp2.Forecast + "</p>");
   Json.Write(temp, Response.Output);
}else{
   Response.Write("Invalid Zip Code");
}

If you were to run this code in a browser from within the Current Weather site you would see the following page output:

Partly Sunny

{"Zip":"92805","Latitude":"33.8263","Longitude":"-117.911","MaxTemp":66,"MinTemp":50,"Forecast":"Partly Sunny"}

Partly Sunny

{"Zip":"92805","Latitude":"33.8263","Longitude":"-117.911","MaxTemp":66,"MinTemp":50,"Forecast":"Partly Sunny"}

The Json Helper contains two methods, Encode and Decode, which are used to convert the Temperature object in and out of a JSON formatted string. Notice that the encoded output has converted the properties of the Temperature object to keys and associated the property data to each key as a string value. When the JSON string is decoded, the properties of the object can once again be accessed as they were prior to encoding. Since we only need to encode and write directly to the response stream, the process can be simplified through the use of the Json.Write method as demonstrated in the last line of code.

A Quick Test

Your final output of the REST service should look something like this:

@{
   var zip = Request.QueryString["zip"];

   if(zip == null){
      Response.Write("Missing Zip Parameter");
      return;
   }

   if(zip != string.Empty){
      var temp = Weather.GetForecastByZipcode(zip);
      Json.Write(temp, Response.Output);
   }else{
      Response.Write("Invalid Zip Code");
   }
}

Now whenever a valid zip code is sent to the service, the requesting client will receive a JSON formatted string that can be decoded by a native JSON parser.

The Windows Phone Client

So far you have seen how easy it is to quickly create a RESTful service with WebMatrix and Razor. Taking advantage of time saving built-in features like the Json Helper, we were able to convert a custom data object into a standardized format in only a few lines of code. In this section we will look at how easy it is for a client that supports HTTP based communication to consume this service to deliver a context specific user interface.

Silverlight for Windows Phone 7 is a lightweight subset of Microsoft’s desktop framework Windows Presentation Foundation. Designed to be a lightweight platform, it enables rapid development of compelling and attractive interfaces for mobile devices. So let’s look at how we can leverage the interactive capabilities of Silverlight to create an attractive weather forecast application that uses the Current Weather REST service.

Creating a User Interface

Silverlight applications are created from a combination of the XML based markup language XAML and C#. The user interface that we will be working with was created using the Microsoft Expression Blend design tool. Expression simplifies the process of creating graphical elements and animations with XAML. Although it is possible to work with XAML directly through a tool like Microsoft Visual Studio, when creating a rich media experience the Microsoft Expression Blend design tool is the preferred approach.

The following screenshots of the Windows Phone emulator demonstrate what the final output looks like. The different forecasts that are returned from the REST service determine which weather icon is displayed. In each screen the depicted weather icon is also performing a simple animation.

clip_image002clip_image004clip_image006

If you would like to get a better idea of how the graphical elements and animations for this application are created, you can view the XAML markup included with the source code for this tutorial. Next, let’s look at how Silverlight communicates with REST service we created in the previous section.

Communicating with the REST Service

If you recall from the last section, a RESTful web service should only communicate over HTTP. In Silverlight, HTTP requests and responses are handled through the WebClient class that is located in the System.Net namespace. Let’s look at how WebClient is used to communicate with the service. The following code is located within the code-behind for the main page of the project, which in this case is named MainPage.xaml.cs.

WebClient weatherClient;

public Page()
{

   InitializeComponent();
   weatherClient = new WebClient();
   weatherClient.OpenReadCompleted += new OpenReadCompletedEventHandler(weatherClient_OpenReadCompleted);
   CheckWeather(new Location(){ City = "Boston", Zip = "02125"});
}

In the code sample above, we simply use the constructor for the class to initialize a WebClient instance called ‘weatherClient’. After the weatherClient object has been created, an event handler is attached to the OpenReadCompleted event. This will allow the page to make a service request without blocking the rest of the application. When the request is completed the OpenReadCompletedEventHandler method will be called. The CheckWeather method is responsible for sending a request to the REST service. We call it right away using a default location so that the Silverlight application displays a weather forecast as soon as loading is finished. The Location type that you see in the method parameter for CheckWeather is a small struct that is used to hold the selected city name and zip code in a single object.

private void CheckWeather(Location location)
{

   UriBuilder uri = new UriBuilder(string.Format("http://{0}:{1}/{2}", “localhost”,5763, "jsonservice.cshtml"));
   uri.Query = "zip=" + location.Zip;
   weatherClient.OpenReadAsync(uri.Uri, location);

}

Whenever the CheckWeather method is called, it assembles a URL for the REST service and places a call to the OpenReadAsync method of the weatherClient object. Notice that the location object is passed again, this time into the optional ‘userToken’ parameter of the OpenReadAsync method. The WebClient class will send any object that is passed here back through the event arguments of the weatherClient_OpenReadCompleted method that was attached in the constructor.

void weatherClient_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{

   if (e.Error != null)
      return;

   Location location = (Location)e.UserState;

   Weather weather = e.Result.Decode<Weather>();

   SetWeather(location, weather);
}

When the REST service returns the request the response will be received by WebClient as a Stream. The Stream can be found in the Result property of the event argument and will contain the JSON string that we created in the last section unless an error has occurred. If the request was successful, the device will now have the requested weather forecast data available for use. However, we still need a way to get the JSON data into an easily readable format. Notice that after the Location object is retrieved from the event arguments, Weather object is created by calling the Decode method on the Stream. Let’s take a closer look at how Decode is used.

Decoding JSON on Windows Phone 7

Unlike the Web version of Silverlight, the Windows Phone implementation does not have a dedicated Json parser available through the API’s. Therefore you will be required to use the DataContractJsonSerializer class found within the System.Runtime.Serialization.Json namespace. This class can be used to serialize and deserialize JSON data to and from an instance of a type.

The Decode<T> method is a generic extension method that simply helps us keep the process of decoding JSON from the response stream.

public static T Decode<T>(this System.IO.Stream stream)
{

   T obj = default(T);
   StreamReader sr = null;

   try
   {

      sr = new StreamReader(stream);
      string json = sr.ReadToEnd();
      var serializer = new DataContractJsonSerializer(typeof(T));
      obj = (T)serializer.ReadObject(stream); 

   } finally
   {

      if (sr != null)
         sr.Close();
   }

   return obj;
}

When the method is called on a Stream an instance of DataContractJsonSerializer is created to deserialize the JSON data. The deserializer will attempt to match JSON keys and values with the properties found in the generic type that is used. Since we know exactly what the JSON format looks like, we can safely create a simple object to hold the data.

public class Weather
{

   public string Zip { get; set; }
   public string Latitude { get; set; }
   public string Longitude { get; set; }
   public string MaxTemp { get; set; }
   public string MinTemp { get; set; }
   public string Forecast { get; set; }

}

Notice that the Weather object is almost identical to the Temperature object used by the Current Weather site. All the properties in the Weather class are left as type String to avoid having to rely on the deserializer to perform unnecessary casting.

Updating the User Interface

Once the JSON data has been successfully extracted, it is passed to the SetWeather method along with the Location object to update the user interface.

private void SetWeather(Location location, Weather weather)
{

   city.Text = location.City;
   temperature.Text = weather.MaxTemp;
   date.Text = DateTime.Now.ToShortDateString();
   condition.Text = weather.Forecast;

   if (condition.Text.Search(sun))
   {
      WeatherIcon.PlaySun();
   } else if (condition.Text.Search(cloud))
   {
      WeatherIcon.PlayOneCloud();
   } else if (condition.Text.Search(snow))
   {
      WeatherIcon.PlayMultipleClouds();
   } else if (condition.Text.Search(rain))
   {
      WeatherIcon.PlayRain();
   } else if (condition.Text.Search(storm))
   {
      WeatherIcon.PlayLightning();
   }
}

Location and Weather information is set and then the forecast description is parsed using a regular expression to find certain keywords. The weather icon animation that is displayed is determined by the match conditions that are supplied.

And that’s it. We have covered all of the steps required to get a Windows Phone application communicating with the REST service we created for the Current Weather site. Although it is a very simple approach, the steps you have observed in this tutorial will enable you to begin building WebMatrix sites that can deliver content to any client with support for HTTP and JSON.

Summary

In this tutorial you saw how WebMatrix can be used to create a RESTful content delivery service that can be consumed by a variety of user interfaces. You also saw how to use Silverlight to create a Windows Phone 7 weather app that could retrieve data from this service.

WebMatrix was created from the ground up to be a simple, all-inclusive web development tool that is easy to use but still powerful enough to deliver the advanced features used by websites today.

Additional Resources

Download WebMatrix http://www.microsoft.com/web/webmatrix/

Learn more http://www.microsoft.com/web/category/learn

More tutorials http://www.asp.net/webmatrix

Twitter http://twitter.com/mswebplatform

Facebook http://www.facebook.com/WebPlatform

For any questions or comments about this tutorial please contact the Aeshen team at http://www.twitter.com/aeshen

You can discuss this article using the adjacent Facebook talkback.

For technical questions please visit our discussion forums, where we have a vibrant community of developers like you, as well as Microsoft engineers who are ready to answer your questions!