Working with Data Services in Silverlight 3: WCF Vs. REST

Code a Silverlight app with WCF and then REST, to help you understand the best uses for each type of service

Downloads
Cleeren_Cooking_with_Silverlight_Code.zip

Click here to download the code for this article.


Since the release of Silverlight 1.0 in May 2007, the platform has evolved substantially. The initial release featured a JavaScript programming model, which made it hard to build a Silverlight business application that required connecting with services and displaying data in a rich manner. Things radically changed with the introduction of Silverlight 2 and even more so with Silverlight 3. Increasingly Microsoft is positioning Silverlight as a platform that's ready to build data-driven, line-of-business applications—by including such features as extensive data-binding support, many (data) controls (e.g., DataGrid, DataForm), the Silverlight Toolkit (an open source project at www.codeplex.com/silverlight), and richer support for communicating with services.

Here I'll delve into the latter Silverlight 3 feature by comparing the options developers have for communicating with services from Silverlight. I'll do so by building a sample application called Cooking with Silverlight, a fictitious site where people can search in a recipe database and read reviews of recipes. I'll start by showing options for exchanging information with a Windows Communication Foundation (WCF) service. After that, I'll build the same application, but now using representational state transfer (REST) services. These two examples will demonstrate the differences between communicating with WCF or REST in a Silverlight app. You can download the complete code for this article by clicking the above link.

Working with Data in a Silverlight App
Silverlight uses the same Base Class Library (BCL) as the full .NET Framework, however, only a subset is available in the Silverlight platform. When browsing the assemblies, you'll quickly notice that many familiar data-related assemblies and classes are missing. Indeed, Silverlight does not contain ADO.NET and has no support for a DataSet or DataReader. In Silverlight 3, the current version at the time of writing, Silverlight has no client-side database access available, and it isn't possible to have a connection string in your Silverlight application, which would allow remote database access.

However, enterprise applications are built around data. To solve this problem, Silverlight can connect with services, on the same server on which the Silverlight app is hosted or on another server, if it complies with a few characteristics, which we'll look at in the cross-domain section of this article. Using services, we can satisfy almost every requirement for working with data in a Silverlight application. Even if we had a client-side database implementation, we'd still have the services required to use up-to-date information.

Out of the box, Silverlight can connect with several types of services, including WCF and REST. Let's first look at how the sample application was built and compare where the two technologies differ from one another.

Cooking with Silverlight
The Cooking with Silverlight website application allows users to search for recipes in a database, based on a keyword. When matching recipes are found, they're displayed in a ListBox. This ListBox has an ItemTemplate applied to it, which allows rich data visualization. The user can then select a recipe and read all the details in the detail window as well as see reviews for the selected recipe. Figure 1 shows the application.

Figure 1: The Cooking with Silverlight application

It should be clear by now that the data lives on the server and will be accessed using services. Let's first examine how the server-side code retrieves the data from the database. The code here uses a typical n-tier approach using a combination of Entity Framework and custom-created business objects. Services will be used to expose this data. The database model is intentionally kept simple and contains only two tables, Recipe and RecipeReview. Figure 2 shows the schema.

Figure 2: Database schema
 
To access the data, Entity Framework is used in combination with a repository for both the Recipe and the RecipeReview. The code in Figure 3 shows a part of the RecipeRepository, where first a context instance is created, followed by a query to find recipes matching the provided search term.

Data will need to travel over the wire. For that, I created my own data contract in the form of a simple data transfer object (DTO) for both the Recipe and the RecipeReview. Figure 4 shows the code for the Recipe data contract. Only types that are marked with the DataContractAttribute will be sent. Each field that should be included must be attributed with the DataMemberAttribute.

With that, the setup is ready; let's now focus on the services. To be able to talk to a service from a Silverlight application, we need to answer two questions:
• How should we design the service so it's accessible from Silverlight?
• How can the Silverlight client application connect with the service?

We'll consider both questions for the combination Silverlight/WCF and Silverlight/REST.

Silverlight and WCF
WCF is the preferred way of building services in the .NET Framework. Designing a WCF service for use with Silverlight isn't much different from designing the service for use with any other technology. The main difference is the type of binding used for the communication. By default, when you add a WCF service to a project, it's configured to use a wsHttpBinding. In general, a wsHttpBinding supports distributed transactions and secure sessions. Silverlight, however, can't work with this type of binding; instead a basicHttpBinding is required. A basicHttpBinding essentially allows communication with a traditional ASMX web service (based on WS-BasicProfile 1.1) and lacks the options offered by the wsHttpBinding, such as secure sessions.

This means that all data is transmitted as plain XML in a SOAP message. In enterprise environments, this could be risky. To counter this risk, one possible solution is using ASP.NET authentication to allow access only to authenticated users on the services. Figure 5 shows the binding as it should be configured in the web.config file of the service project.

Visual Studio offers a Silverlight-enabled WCF service template. This template sets the correct type of binding in the configuration file.

Creating the WCF Service
A WCF service typically offers a service contract. The service contract offered by the service defines the operations exposed by the service. Each operation that needs to be exposed over the service is attributed with an OperationContractAttribute. In Figure 6, the SearchRecipesByName operation is shown as part of the service contract. It defines that, based on the search term entered by the user, a list of Recipe instances will be returned.

The implementation of the service, contained in the *.svc.cs file in a WCF scenario, contains the logic for accessing the data using the repository and returning a list of DTOs. Figure 7 shows the implementation for the SearchRecipesByName operation, which returns a List. The service is now ready to be accessed from a Silverlight application.

Using the WCF Service from the Silverlight Client
With the service in place, the Silverlight application needs to connect with it. WCF services are said to be self-describing: They expose a Web Services Description Language (WSDL) file, which contains metadata about the service. This metadata describes, among other things, the operations and data contracts exposed by the service. When you connect to such a service using Visual Studio's Add Service Reference dialog box, the IDE will generate a proxy class. This proxy contains a client-side copy of the service. The proxy class contains all operations, without the implementations, and a copy of the data contracts. Because of this, we get full IntelliSense in the editor when working with the service.

To execute a call to the service, we use this proxy class. However, when the application accesses a service from Silverlight, the call will be executed asynchronously. If synchronous calls were possible, during the call's execution the browser would remain blocked while awaiting a response from the server. Looking at the code in Figure 8, it's easy to see that the call to the service is done in an asynchronous manner.

A callback method is specified for the XXX_Completed event. This method is executed when the service returns. Making the actual async call to the service is done using the XXXAsync method. Inside the callback method, the result of the service call is accessible through the e.Result property. This property's type is the same type as returned by the service. These types were generated when the proxy was created upon adding the service reference. We're using the result, here a generic List of Recipe instances, as the ItemsSource for the ListBox. Of course, other data-binding scenarios are possible here.

More WCF Options in Silverlight 3
Since Silverlight 3, more options have become available when working with WCF services. Silverlight now supports the Binary XML data format. This lets us format the XML into a binary format, which results in smaller message sizes and can greatly improve communication speed. To use this format, you must add a new behavior in the service's configuration, as Figure 9 shows.

Duplex communication is also much easier in Silverlight 3 than it was in Silverlight 2, which required deep knowledge of WCF to implement this. However, this topic is outside the scope of this article; you can learn more about it at msdn.microsoft.com/en-us/library/dd470106(VS.95).aspx.

Silverlight and REST
The biggest advantage of using WCF services is the typed access, which is based on the metadata that the service exposes. This makes the process of writing the client-side code easier. However, not every service exposes metadata. Some services work with human-readable information, mostly in the form of XML, which they send following a request from the client.

This is the case for REST services. Compared with WCF, REST has some advantages. As said, the information is exchanged as pure XML (or JavaScript Object Notation—JSON, if needed). The XML is clean and more lightweight than the SOAP messages exchanged when using WCF. Thus, less data will go over the wire, resulting in faster transfer of the data. REST is also entirely platform independent: It requires no extra software as it relies on standard HTTP methods. However, because REST services are not self-describing, Visual Studio can't generate a proxy class. This means that when writing a Silverlight application that needs to work with a REST service, we manually need to parse the returned XML to capture the server's response. Luckily, Silverlight includes LINQ to XML, making this process much easier. Alternatively, you could use the XmlReader/XmlWriter or the XmlSerializer for this task.

Let's again look the two questions: how to create the service and how to access it from Silverlight.

Creating the REST Service
A REST service will send data when it's requested to do so. The request is done over HTTP, for example, by sending a request to a specific URL. The REST service will then respond by sending XML over the wire.

To create a REST service, we can use WCF as well. However, we need to perform some configuration changes to enable the WCF services to work as REST services. Figure 10 shows how the system.serviceModel in the web.config file should be configured for using WCF services as REST services.

The service operations in the service contract need to be attributed with WebGetAttribute in addition to the OperationContractAttribute. The UriTemplate defines what the URL should look like and which parameters it should contain to get access to the associated operation. In Figure 11, the SearchRecipeByName operation can be accessed by appending /recipe/find/\\{searchTerm\\} to the URL of the service, with searchTerm being a parameter.

The implementation of the service operation is almost identical to the WCF implementation, as you can see in the previous listings. To test the service and see its response, navigate for example to http://localhost:1234/ RestRecipeService.svc/recipe/find/pancake. Figure 12 shows the XML displayed in the browser. This XML is basically the contract that the REST service provides: the returned XML will always be in this format. This is important when using this XML in client-side code, as we will need to write XML parsing code.

For the sample application, we wrote the REST service ourselves. It's also possible to use one of the numerous, often free, REST service APIs available, such as Twitter, Flickr, or Facebook. Looking at those APIs, it's easy to see that their XML is also the contract for data exchange between a client application and the service.

Using the REST Service from the Silverlight Client
Since there's no metadata available on a REST service, we can't add a service reference to it from Visual Studio. We need another approach.

Using a REST service from Silverlight is a three-step process. Step one: Build the URL to which we need to send a request. The format of this URL is defined by the service and may contain parameters that we must provide as well. Step two: Send a request to that URL. And finally, step 3: Wait for the result to come in as XML or JSON and parse this accordingly.

Building the URL is pretty straightforward. It's constructed by gluing together the URL from the service project with the string defined as value for the UriTemplate. You can send a request to this URL by using either the WebClient or the HttpWebRequest class, both part of the System.Net namespace and also classes included in the full .NET Framework. For most situations, the WebClient will suffice; if you need more fine-grained control over the request, the HttpWebRequest is the best bet. The WebClient is basically a wrapper around the HttpWebRequest with an easier API: Using the WebClient under the covers still uses methods of the HttpWebRequest. We'll use the WebClient here as well.

In Figure 13, we're performing both step one and two. An instance of the WebClient is created, and the request is sent asynchronously. Similarly to working with WCF, requests being sent to a REST service must be sent synchronously. The composed URL is used as the parameter for the DownloadStringAsync() method.

The callback method specified in Figure 12 for the DownloadStringCompleted will be called when the REST service has sent its response. Depending on the service, this response is mostly XML and in some cases JSON. In the Silverlight application, this result can be parsed using LINQ to XML, as shown in Figure 14. A custom type called Recipe, created manually (remember, there's no code generation as we had with WCF), is used here as well.

Cross-Domain Access
When accessing services, Silverlight will not allow access of these services by default if they're hosted on a domain other than the domain hosting the Silverlight application. In other words, if we have a Silverlight application called CookingWithSilverlight.xap hosted on http://www.somedomain.com, the application can't access a service on http://www.someotherdomain.com unless that service specifically grants a right to access it from a client application hosted on another domain. This feature is called cross-domain restrictions and is basically a security measurement to prevent cross-domain attacks.

How can a service allow the access anyway? When a cross-domain service request is launched, Silverlight will check for a file called ClientAccessPolicy.xml at the root of the domain (it will also check for crossdomain.xml, which is the policy file that Adobe Flash checks for). If this file is present and allows the call to be made, Silverlight will access the service. If the file isn't present or we're accessing from a domain that isn't on the list of allowed domains, Silverlight will block the request, resulting in a security exception being thrown.

Cross-domain restrictions apply for both WCF and REST services. Accessing an image or a video on another domain doesn't trigger this check. In the sample application, both the WCF and REST services are hosted in a website different from the one hosting the Silverlight application. In both websites, at the root, a policy file can be found, allowing access from any domain. Figure 15 shows this XML file. If only some domains can access the service, they can be listed in the uri attribute of the domain element.

Two Services Options for Silverlight Developers
Both WCF and REST have their strong points. WCF really benefits from the fact that it exposes metadata that can be used to generate a proxy class. During development, this results in IntelliSense picking up the types and operations of the services, which makes things much easier. Features like easy duplex communication and binary XML data exchange make WCF in Silverlight quite complete. All SOAP 1.1–enabled services, even if they're exposed from technology other than .NET, can be used from Silverlight in the same manner. In most enterprises, SOAP-enabled services are the standard.

However, we don't always have—or need—all the options made available by WCF. If the data being exchanged is pure text, we can use REST. It's simple, fast, and is based on the HTTP standard methods, requiring no special software. Many large Web 2.0 sites expose an API that uses REST. Working with this type of services does require some more manual work, in that we have to send the request, capture the results, and parse them into meaningful data.

Regardless of what type of service is used, the communication happens asynchronously. In the case of WCF, when the proxy class is generated, both the XXXAsync method and the XXX_Completed event are created. When using REST, the WebClient has a DownloadStringAsync and a DownloadStringCompleted event.

Gill Cleeren is a Microsoft Regional Director, an ASP.NET MVP, and a Silverlight insider. He lives in Belgium and works for Ordina as .NET architect. Gill is also the author of the upcoming Silverlight Data Access Cookbook and blogs at www.snowball.be.

Hide comments

Comments

  • Allowed HTML tags: <em> <strong> <blockquote> <br> <p>

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.
Publish