This article is compatible with the latest version of Silverlight.
Introduction
For its data needs, Silverlight needs to connect to a service. Since Silverlight is a client-side technology, services are the way for Silverlight to get to data that resides on the server. In the current release, there is no support for any ADO.NET related functionality (so no DataReaders, DataSets and no LINQ-To-SQL). That means we can’t connect from Silverlight to a database available on some server by simple using a connection string and creating a connection from the Silverlight client. If we do want access to that data, we need to place a service in front of the database (that in most cases will call a business layer that in turn will call a data access layer that in its turn will access the database).
Luckily, Silverlight 4 is very rich in the number and types of services it can work with. Silverlight can easily connect with WCF/ASMX services. These services are said to be self-describing, as they expose a WDSL endpoint that we can connect to. A WSDL endpoint exposes all the information about the service (supported methods, supported data types) and is used by Visual Studio to create a client-side proxy. This proxy can then be instantiated in our Silverlight code to communicate with the actual service. This type of service communication sends the data using SOAP. SOAP is a messaging format that is XML, however, the data is wrapped in a SOAP envelope. This can be seen as an overhead, since quite a lot of extra information is sent for each message on top of the actual data. On the other hand, using WCF gives us the most options in Silverlight, including duplex messaging, debugging of services etc.
Thinking back of the mentioned overhead: in some situations, we don’t always need all the features offered us by WCF. In some cases, we only need to send or receive pure textual information, mostly in XML format. We may not need all the extra features added when exchanging our data in SOAP format. In this situation, another protocol is supported in Silverlight called REST (REpresentational State Transfer). REST is becoming a very popular format to use: many large web applications (I call them applications, since they are more than merely a web site) such as Facebook, Twitter and YouTube offer (part of) their functionality for us to use in our applications as REST services (forming a REST API).
In this article, we are going to take a look at what options we have to connect to REST services from our applications. For this article, we’ll use a REST service that we create ourselves first. The service is a sample weather service that can return and update some weather information. This type of service is a good candidate for a REST service: there’s no data going over the line that needs to be secured (weather information can hardly be called sensitive data…) and since this is general purpose service, many third party systems may wish to connect to our service. Since REST is based on standards, it can easily be used from any technology. The UI of the application can be seen here:
The source code for this article can be downloaded here.
Don’t worry, take some REST
As said, REST is a protocol that uses plain text to exchange information. The information is mostly in XML or JSON. As most of the sent data is “actual data”, there’s less overhead than when using WCF. One of the basic principles of REST is that all data should be addressable using a URL. This data is then considered a resource. The WWW can be seen as a large REST implementation: each resource (a page in this case) has a unique URL that can be used to access it.
Another advantage of REST is that it is platform independent, since it uses basic HTTP verbs (such as GET). This results in the fact that a REST service written in any technology can be used by Silverlight. Using WCF, it’s actually very easy to create a REST service, as we’ll see in this article. Services that communicate over REST are said to be RESTful services.
Silverlight wants some REST
OK, I’m done with the REST jokes. Let’s take a look at what we need to do to connect to our own written REST service.
Creating the REST service
To connect to a self-written REST service, the first step is of course, authoring it. Using WCF, this is actually very easy. In the sample, there are 2 services that return data: the first one returns the forecasted weather for tomorrow, the second one returns a five day forecast.
To write a REST service, start by adding a Silverlight-enabled WCF service. In this case, the service is called WeatherService.svc. At this point, this is a “normal” WCF service. To make the operations work over a REST call, add the WebGet attribute on the operation. The UriTemplate specifies the address of the method within the service: for example, if our service is WeatherService.svc and the UriTemplate is set to “tomorrow”, the method can be called using WeatherService.svc/tomorrow. Furthermore, the RequestFormat specifies that this service will return information over XML here (JSON is the second option).
[OperationContract]
[WebGet(UriTemplate = "tomorrow", BodyStyle = WebMessageBodyStyle.Bare,
RequestFormat = WebMessageFormat.Xml)]
public DayWeather TomorrowWeather()
{
//Mocking this data here
return WeatherRepository.TomorrowWeather;
}
To get it working, we also need to perform some configuration changes. In the Web.config, the following changes need to be done:
- Add the webHttp behavior to the endpoint behaviors:
<behaviors>
...
<endpointBehaviors>
<behavior name="webBehavior">
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
- Make sure this behavior is used for your service:
<service name="RESTWeather.Web.WeatherService">
<endpoint address="" behaviorConfiguration="webBehavior"
binding="webHttpBinding" contract="RESTWeather.Web.WeatherService" />
<endpoint address="rest" behaviorConfiguration="webBehavior"
binding="webHttpBinding" contract="RESTWeather.Web.WeatherService" />
</service>
We can now test this service using the following URL:
http://localhost:6568/WeatherService.svc/tomorrow
The response is as expected XML:
<DayWeather xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<DayTemperature>-3</DayTemperature>
<Forecast>Snow</Forecast>
<NightTemperature>-8</NightTemperature>
</DayWeather>
From our Silverlight application, we can now make a call to this REST service.
Connecting and reading from the REST service
Because a REST service does not have an endpoint to which we can create a service reference, we need another way of communicating with it. The easiest, and in most situations, best solution is using the WebClient class (alternatively, the HttpWebRequest can be used). This class, which lives in the System.Net namespace also exist in the regular .NET framework and can be used to send a request to a URL and capture the response.
Communicating with a REST service (and for that matter, any POX (Plain Old Xml) service), requires us to follow these 3 steps:
- Create the URL to which we need to connect
- Send a request to this URL
- Capture and parse the result (in our case, XML)
In the sample, the URL is hardcoded:
private string baseUrl = "http://localhost:6568/WeatherService.svc/";
private string tomorrowForecastUrlSuffix = "tomorrow";
When the user now clicks on the Tomorrow HyperlinkButton, the following code is executed:
private void TomorrowLink_Click(object sender, RoutedEventArgs e)
{
//build up URL
string tomorrowForecastUrl = baseUrl + tomorrowForecastUrlSuffix;
GetWeatherFromRestService(tomorrowForecastUrl);
}
private void GetWeatherFromRestService(string tomorrowForecastUrl)
{
WebClient client = new WebClient();
client.DownloadStringCompleted += (s, ev) =>
{
XDocument xml = XDocument.Parse(ev.Result);
var weather = from results in xml.Descendants("DayWeather")
select new DayWeather
{
Forecast = results.Element("Forecast").Value.ToString(),
DayTemperature = Int32.Parse(results.Descendants("DayTemperature").First().Value),
NightTemperature = Int32.Parse(results.Descendants("NightTemperature").First().Value),
};
ObservableCollection<DayWeather> dayWeatherList = new ObservableCollection<DayWeather>(weather.ToList());
ForecastListBox.ItemsSource = dayWeatherList;
};
client.DownloadStringAsync(new Uri(tomorrowForecastUrl));
}
This code executes the above mentioned steps. It uses the URL of the REST service. Then, it sends a request to this service URL using the WebClient class. As with all other communication, this call happens asynchronously. Using the DownloadStringAsync, we perform the actual call; in the callback, we get in the e.Result parameter the XML as it was retrieved from the service. We are responsible ourselves for the parsing of this XML, this is in contrast to using a WCF/ASMX service where this is done for us.
We use Linq-To-XML here, as it is the easiest way to parse XML. Silverlight has other options on board though, including the traditional XmlReader. The Five Day Forecast is similar and can be found in the sample code.
Now that we know how to read from a REST service, can we also use it to save data back to the server?
Saving data using REST
A REST service is capable of accepting data. Remember that we mentioned that REST uses standard HTTP methods? Well, we can use exactly that to perform saving of data. Let’s first create a service method for this as follows:
[OperationContract]
[WebInvoke(UriTemplate = "tomorrow/update", Method = "POST", RequestFormat = WebMessageFormat.Xml)]
public void UpdateTomorrowWeather(DayWeather newWeather)
{
WeatherRepository.TomorrowWeather = newWeather;
}
Note that the Method parameter is now set to POST, indicating that our client can using the standard HTTP Post method send data to the service.
In the Silverlight client, we can now use this method to perform a save operation over REST. In the code below, we are doing exactly that, again based on the WebClient. We however need to perform some more work ourselves. We need to serialize the data we want to send into an XML string. Also, the headers need to be set on the request to XML. Finally, we need to use the UploadStringAsync method of the WebClient to upload the XML to the REST service, specifying that we want to do a POST.
WebClient client = new WebClient();
string updateWeatherUri = baseUrl + updateTomorrowSuffix;
DataContractSerializer dataContractSerializer =
new DataContractSerializer(typeof(DayWeather));
MemoryStream memoryStream = new MemoryStream();
dataContractSerializer.WriteObject(memoryStream, _dayWeather);
string xmlData = Encoding.UTF8.GetString(memoryStream.ToArray(), 0, (int)memoryStream.Length);
client.UploadStringCompleted += (s, ev) =>
{
if (ev.Error == null)
this.DialogResult = true;
};
client.Headers[HttpRequestHeader.ContentType] = "application/xml";
client.UploadStringAsync(new Uri(updateWeatherUri), "POST", xmlData);
Conclusion
The REST protocol is popular and that’s easy to understand. It’s supported on most technologies and of course, Silverlight is one of them. REST services can be used from Silverlight to perform read and save operations. A bit more work is required though, since there’s no automatic serialization happening because of the lack of a WSDL file within the REST service.
About the author
Gill Cleeren is Microsoft Regional Director (www.theregion.com), MVP ASP.NET, INETA speaker bureau member and Silverlight Insider. He lives in Belgium where he works as .NET architect at Ordina. Passionate about .NET, he’s always playing with the newest bits. In his role as Regional Director, Gill has given many sessions, webcasts and trainings on new as well as existing technologies, such as Silverlight, ASP.NET and WPF. He also leads Visug (www.visug.be), the largest .NET user group in Belgium. He’s also the author of “Silverlight 4 Data and Serivices Cookbook”, published by Packt Publishing. You can find his blog at www.snowball.be.