Using ASP.NET Razor Syntax with Silverlight

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 Silverlight 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 XAML, C# and 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 consumable by other applications.

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 Silverlight 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.

One of the more compelling options for creating rich interactive user interfaces is the Microsoft Silverlight platform. 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 pictures highlight some of the various weather icons and the overall weather forecast client interface that will be displayed on the Current Weather page. In each screen the depicted weather icon is also performing a simple animation.

img1img2

img3img4

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. Using the Code-Behind for the main page of the weather application, let’s look at how WebClient is used to communicate with the service.

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}, 
HtmlPage.Document.DocumentUri.Host,HtmlPage.Document.DocumentUri.Port, "/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 again, that the location object is passed into the optional ‘userToken’ parameter of the OpenReadAsync method. The WebClient class will send any object that is passed here back through the 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;
    JsonValue json = JsonValue.Load(e.Result);
    SetWeather(location, json);
}

Notice how in the event handler, the event argument object exposes the properties ‘UserState’ and ‘Result’. The UserState property contains a reference to the Location object. The Result property contains the response stream sent from the REST service and will contain the JSON formatted weather forecast data sent from the Current Weather site. Since we know that the service is delivering data that is in the JSON format we can take advantage of the Json libraries that are available in Silverlight. The first step is to use the JsonValue.Load method to parse the response stream into a JsonValue object. Then the JSON and Location data is passed to the SetWeather method where it will be evaluated and rendered to the user interface.

private void SetWeather(Location location, JsonValue weather)
{
    city.Text = location.City;
    temperature.Text = weather["MaxTemp"].ToString();
    date.Text = DateTime.Now.ToShortDateString();
    condition.Text = (String)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();
    }
}

The JsonValue object holds the key/value pairs from the original JSON string. Individual values can be accessed by either a numeric indexer or the name of the key. After the location information has been set, 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.

At this point we have covered all of the steps required to get Silverlight 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 learned how to use WebMatrix to create a RESTful web service that is capable of delivering content to a range of web supported applications and devices. You saw how the Silverlight platform is perfectly suited for delivering WebMatrix content to users through a rich interactive interface.

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!