Connecting the iPhone 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 an iPhone 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 HTML, CSS, JSON 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 an iPhone.

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.

An iPhone Client

RESTful web services that rely on open standards are the ideal way to enable your site to deliver content to a variety of disparate systems. Practically every popular computing platform available today is capable of sending and receiving data over HTTP. In this section we will explore the benefits of building REST services by looking at how an iPhone app can consume the weather service we just created.

iPhone Apps

Apps that are written for the iPhone are typically written in the Objective-C language. If you are used to working with JavaScript or C# then the Objective-C code that you will be looking at may seem a little foreign. If so, not to worry, the goal here is to simply get show how WebMatrix can be used to create sites that can interact with iPhone applications.

A typical iPhone app is created using the Xcode IDE from Apple. Xcode is the standard tool for creating OS X and iOS apps. We will be adding some code to a View-Based Application project for the iPhone OS called WeatherApp. This app will display the weather data in a simple label on a view controller form. We will be working with two new files that have been added to the project, the header file WeatherAppViewController.h and the implementation file WeatherAppViewController.m.

Communicating with the REST Service

If you recall from the last section, a RESTful web service should only communicate over HTTP. iPhone applications that need make HTTP requests use the NSURLConnection and NSURLDownload classes to request and receive responses from an HTTP source. Let’s take a look at how these classes are implemented to enable communication with the CurrentWeather REST service.

The first thing we need to is override the viewDidLoad method of the WeatherAppViewController for the application by adding the following code to the WeatherAppViewController.m file. When this method is called, we will make an NSURLRequest to the jsonservice.cshtml we created earlier.

-(void)viewDidLoad {

   [super viewDidLoad];

   jsonData = [[NSMutableData data] retain];

   NSURLRequest *request = [NSURLRequest requestWithURL: [NSURL URLWithString: @http://localhost:5763/jsonservice.cshtml?zip=92805]];

   [[NSURLConnection alloc] initWithRequest:request delegate:self];

}

The first thing that we do is initialize an NSMutableData object that will be used to store the data returned from the service. The jsonData object is declared in the WeatherAppViewController.h header file accordingly:

@interface WeatherAppViewController : UIViewController {

   NSMutableData *jsonData;

}

@end

The NSURL class is a simple URL container object that ensures that calls with NSURLRequest are properly formatted. The initWithRequest method of the NSURLConnection class uses the request to the service to initiate a connection and begin receiving the response data. When NSURLConnection receives a response it raises the didReceiveData method and passes in the response data as a method parameter.

-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {

   [jsonData appendData:data];

}

As responses are received we simply append the data to the jsonData object that initialized in the viewDidLoad method. When the NSURLConnection has finished receiving data, it will raise the connectionDidFinishLoading method.

-(void)connectionDidFinishLoading:(NSURLConnection *)connection {

   [connection release];

   NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];

   [jsonData release];

}

We can use this method to begin parsing the JSON formatted data into a format that is readable by the application. In this case, we simply convert the jsonData object to an NSString. The NSString type will essentially return the JSON response back to its original format. The last thing we need to do is extract the key and value information from the JSON string.

Decoding JSON

The base iPhone libraries do not contain any native ability to encode and decode JSON formatted strings. Therefore for this example we will be using a helper library that is publicly available for use in iPhone applications called “JSON library”. This library can be downloaded and added to any Xcode project. To use the library, you simply add an import statement to the implementation file where you plan to write JSON encoding or decoding logic. For this project, we just need to add the following statement to the top of the WeatherAppViewController.m file like so:

#import “JSON.h”

To keep things simple, let’s update the connectionDidFinishLoading file to take advantage of the JSON library’s decoding capabilities.

-(void)connectionDidFinishLoading:(NSURLConnection *)connection {

   [connection release];

   NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];

   [jsonData release];

   NSArray *weatherData = [jsonString JSONValue];

   [jsonString release];

   For (int I = 0; I < [weatherData count]; i++)

      [text appendFormat:@”%@\n”, [weatherData objectAtIndex:i]];

      label.text = text

}

The first thing we do is parse the response data that is stored in the jsonString object using the JSONValue class from the JSON library that we added. This will break the JSON formatted string up into an array of key/value pairs. Then we use a loop to iterate through the array and extract each key and value and write to a label in the view. Now whenever the WeatherApp is loaded on an iPhone it will connect to the CurrentWeather site and display the weather data in a custom form. Although it is a fairly simplistic overview you can see how creating a RESTful web service in WebMatrix enables easy access to your content by a range of devices, including the iPhone.

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 a completely different platform like the iPhone is capable of communicating with a WebMatrix site in only a few lines of code.

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!