The Open Data Protocol (OData) is based on an entity and relationship model that enables you to access data in the style of representational state transfer (REST) resources. OData enables the use of the standard HTTP protocol to execute queries, and even to create, update, and delete data from a remote data service. By using the OData support in the Windows Phone SDK, your Windows Phone application can consume data from a Windows Azure service or any other service that supports the OData protocol. The client library lets you compose Language Integrated Query (LINQ) queries against an OData service and transforms the data in the response feed into objects on the client.
Note
This quickstart targets Windows Phone 7.5 development by using the Windows Phone SDK 7.1. This version of the Windows Phone SDK provides support for accessing data from Open Data Protocol (OData) feeds that was not provided in previous versions of the SDK.
This QuickStart contains the following sections:
The live sample in this QuickStart use Silverlight running in the browser to simulate the behavior in Silverlight for Windows Phone. The actual behavior may be slightly different in the Windows Phone emulator or on a Windows Phone device. You can download the completed project from Consuming a Windows Azure Data Service with the OData Client for Windows Phone on MSDN Developer Samples.
Mobile device applications rely heavily on remote data sources, and the Windows Azure platform provides an excellent source of data for your Windows Phone application. OData is one of the primary data access mechanisms of the Windows Azure platform. Various components of the Windows Azure platform produce OData feeds, including Windows Azure Table Storage, Microsoft SQL Azure, and Windows Azure Marketplace DataMarket. A comprehensive list of public OData feeds is available at the Open Data Protocol Web site.
You can also use WCF Data Services to expose your own data as OData feeds that can be consumed in applications that run on a variety of platforms, including Windows Phone. For more information, see WCF Data Services.
As an example, Netflix exposes their catalog of movies as a cloud-based OData feed. We consume this public OData feed in the following live sample that is the basis for this QuickStart:
Click the OData on Phone tile to start the live OData service sample. On the phone, when you tap the Next Page button the next page of data is loaded from the data service. When you tap an item in the list, detailed information about the selected title is displayed. In this example, the Back button works like it does on the phone by navigating you back to the previous page. You can download the complete project for this Windows Phone application from the Silverlight for Windows Phone project in the MSDN Code Gallery Web site.
In the OData client library for Windows Phone, the DataServiceCollection class represents a dynamic data binding collection that provides notifications when items get added to or removed from the collection. A URI-based query determines which data objects the binding collection will contain. This URI is specified as a parameter in the LoadAsync method of the DataServiceCollection class. When executed, this method returns an OData feed that is materialized into data objects in the binding collection. The materialized objects are managed by the DataServiceContext that is associated with the binding collection. The LoadAsync method of the DataServiceCollection class ensures that the results are marshaled to the correct thread, so you do not need to use a Dispatcher object. For more information about working with the OData client library for Windows Phone, see Open Data Protocol (OData) Overview for Windows Phone.
Because Windows Phone applications require navigation between multiple pages, you should use a Model-View-ViewModel (MVVM) design pattern for your data applications. In this pattern, the model is generated by tools based on metadata returned by the data service, the view is comprised of all the data bound controls on the page, and the ViewModel is a shared component that does the work of accessing the data service and exposing the data that is bound to the view. By using this approach, you can expose the DataServiceContext as a property of the view model class, along with properties that return DataServiceCollection instances or any other dynamic values that are bound to controls in the view. The view model must also expose any properties that need to be stored when the application is deactivated, which we will discuss in a later section. The following object diagram represents the MainViewModel class for this example:

The following example shows the definitions for the properties in the MainViewModel class that expose DataServiceContext and DataServiceCollection instances:
// Defines the root URI of the data service.
private static readonly Uri rootUri = new Uri("http://odata.netflix.com/v1/Catalog/");
// Define the typed DataServiceContext.
private NetflixCatalog _context;
// Define the binding collection for Titles.
private DataServiceCollection<Title> _titles;
// Gets and sets the collection of Title objects from the feed.
public DataServiceCollection<Title> Titles
{
get { return _titles; }
private set
{
// Set the Customers collection.
_titles = value;
// Register a handler for the LoadCompleted callback.
_titles.LoadCompleted += OnTitlesLoaded;
// Raise the PropertyChanged events.
NotifyPropertyChanged("Titles");
}
}
' Defines the root URI of the data service.
Private Shared ReadOnly _rootUri As Uri = New Uri("http://odata.netflix.com/v1/Catalog/")
Private _isDataLoaded As Boolean
' Define the typed DataServiceContext.
Private _context As NetflixCatalog
' Define the binding collection for Titles.
Private _titles As DataServiceCollection(Of Title)
' Gets and sets the collection of Title objects from the feed.
Public Property Titles As DataServiceCollection(Of Title)
Get
Return _titles
End Get
Set(value As DataServiceCollection(Of Title))
' Set the Titles collection.
_titles = value
' Register a handler for the LoadCompleted callback.
AddHandler _titles.LoadCompleted, AddressOf OnTitlesLoaded
' Raise the PropertyChanged events.
NotifyPropertyChanged("Titles")
End Set
End Property
The MainViewModel class itself is exposed as a static property of the root application class (app), as is shown in the following:
static MainViewModel _viewModel = null;
// A static ViewModel used by the views to bind against.
public static MainViewModel ViewModel
{
get
{
// Delay creation of the view model until we need it.
if (_viewModel == null)
{
_viewModel = new MainViewModel();
}
return _viewModel;
}
}
Shared _viewModel As MainViewModel = Nothing
' A static ViewModel used by the views to bind against.
Public Shared ReadOnly Property ViewModel As MainViewModel
Get
' Delay creation of the view model until we need it.
If _viewModel Is Nothing Then
_viewModel = New MainViewModel()
End If
Return _viewModel
End Get
End Property
The view model is set as the DataContext of the page, which enables us to bind the ListBox control in MainPage.xaml to the DataServiceCollection returned by the Titles property of the MainViewModel class. You can see in the following XAML example that the ListBox and a few other elements are bound to properties of the MainViewModel:
When the MainPage.xaml page loads, the IsDataLoaded property on the view model is checked. When the data is not already loaded, the LoadData method on the view model is called to set the binding objects and request titles from the data service.
When the LoadAsync method is called, the client library asynchronously sends a query request to the OData service that returns an Atom feed of Title entries. When the response is received, the LoadCompleted event is raised and the entries in the feed are materialized by the client library into objects in the Titles collection, which is bound to the ListBox control.
OData defines a mechanism for accessing binary data separate from the entity to which it belongs. In this way, a data service can expose large binary data as a media resource that belongs to a media link entry. In the Netflix catalog, the Title entity is a media link entry with a related media resource, which is the box art for the title. The GetReadStreamUri method on the view model calls the GetReadStreamUri method on the DataServiceContext to return the URI of the media resource. The following example shows the definition of a StreamUri extension property that returns the URI of the media resource for binding:
In this example, the StreamUri property calls the GetReadStreamUri method to return the media resource URI, which is the box art image. When we bind the StreamUri property to the Source attribute of an Image control, the returned URI is used to download and display the box art for each Title.
Recommendation
For a media link entry, we recommend that you get the URI of the media resource by calling GetReadStreamUri rather than from some other property on the entity. Although the URI of the media resource works well in this case to create an image on the client, other DataServiceContext methods can be used to access and change media resources as a binary stream.
In this example, a typed DataServiceQuery is constructed by using LINQ and the paging parameters defined in the application. In OData there are two different kinds of paging. A client can use the Take and Skip LINQ methods to limit the number of entries in the response to a logical page instead of the full feed. These LINQ query methods are translated by the OData library into $top and $skip system query options in the request URI. The data service itself can also limit the number of entries returned in a given response, where the response contains a continuation token that is used to get the next page of data from the data service.
Because the client is not able to determine whether a data service implements server-driven paging or even the page size, you should consider implementing client paging in your Windows Phone applications to prevent a query returning a very large feed, which can take time and consume valuable phone resources. You should also be prepared to handle server-driven paging in your application.
The following shows the GetQuery method from this example that returns the strongly-typed DataServiceQuery, which is created based on variables passed to the Take and Top parameters.
In this example, the page size is fixed, and the number of entries to skip is calculated based on the current page count. When we load the first page, we also call the IncludeTotalCount method on the query to request a total count of all Title entities, which is used to calculate total number of pages that is displayed in the TitlesPage.xaml. Calling the IncludeTotalCount method adds the $inlinecount=allpages system query option to the query URI generated by the library.
When the response is received, the client raises the LoadCompleted event. When there are additional pages to load because of server-driven paging, the Continuation property of the DataServiceCollection returns a continuation token. The following method handles the LoadCompleted event to load all server-driven pages:
Note that we also read and store the TotalCount value when it is requested in the query. This value is used to calculate and display the total number of pages. Because an updated TotalCount changes the value of the PagesLoadedText property, we also report this change to the binding.
The next logical page of data is requested when the user presses the Next Page button in MainPage.xaml. While you could create a new DataServiceCollection based on the URI that returns the next page, the following example instead uses navigation to load a specific page of data:
This navigation essentially reloads the MainPage.xaml page with the page count of the next page. When the MainPage.xaml page is navigated to, a specific page of data is loaded from the data service, as follows:
By using navigation to load subsequent pages, when the user presses the Back button the default behavior is to reload the previous page. Without the navigation, you would have to override the OnBackKeyPress method to load the previous page of data.
When the user presses a Title in the ListBox control, the following method navigates to the TitlesDetailPage.xaml for the selected Title:
In the TitleDetailsPage.xaml page, the selected index value is used to bind the correct Title from the Titles collection, as follows:
Applications are typically put into a dormant state when the user navigates away. In this state, the application is preserved in memory so that if the user returns to the application, it can resume almost instantly. This fast application switching is enabled automatically. However, it is still possible that an application will be terminated while it is dormant. To enable the application to be reactivated correctly, loaded data, object state information, and certain view model properties must be stored in the state dictionary. The OData client for Windows Phone includes a DataServiceState class that is used to serialize the DataServiceContext and a collection of DataServiceCollection objects so that this data can be stored in a state dictionary. The following SaveState method in the view model returns the serialized state as a string object in a key-value pair collection of items, along with other view model data that must be persisted:
The following method handles the Deactivated event and calls the SaveState method to store view model data when the application is deactivated:
When the application is reactivated, view model is retrieved from the state dictionary. The following method handles the Activated event to restore the application to the previous state:
In the following RestoreState method, the DataServiceState object and other stored data are acquired from the global state dictionary and used to reinitialize the view model:
You can use the Add Service Reference dialog box in Visual Studio to add a reference to any service that exposes an OData feed. This tool connects to the data service and generates the data classes and the data container, which inherits from the DataServiceContext class. The following is how the Add Service Reference dialog box looks when you add a reference to the Netflix OData service:
var gDomain='m.webtrends.com'; var gDcsId='dcschd84w10000w4lw9hcqmsz_8n3x'; var gTrackEvents=1; var gFpc='WT_FPC'; /*<\/scr"+"ipt>");} /*]]>*/