Fun with OData and Windows Phone 7

Tonight I’m speaking in San Francisco on one of my favorite topics, OData. Here’s the info: Creating and Consuming OData Services for Business Applications. (By the way, the Open Data Protocol (OData) is a protocol for querying and updating data over the web. If you’re not familiar with OData I encourage you to check out www.odata.org and come to my talk tonight!)

Since I’ve done this talk a couple times I thought it would be a good idea to add some new demos. One that I thought would be fun would be using OData in a Windows Phone 7 application. It turns out that it’s actually pretty easy do once you have all the right tools and libraries. Here’s what you’ll need:

Get the Tools

Windows Phone Developer Tools RTW – This includes Visual Studio 2010 Express but if you already have VS 2010 Pro or higher the Windows developer tools will just integrate into those versions. It also gives you Expression Blend, XNA Game Studio, and a nifty phone emulator and deployment tools.

Visual Basic for Windows Phone Developer Tools RTW – This allows you to develop Windows Phone 7 apps using Visual Basic. It’s a really light-weight install and includes the project templates you need to build phone apps with VB.

OData Client Library for Windows Phone 7 – You can grab just the binaries and client proxy generator in the ODataClient_BinariesAndCodeGenToolForWinPhone.zip. You’ll need to add a reference to the Windows Phone 7 OData client library in your phone projects to use OData.

Create the Project

First thing to do is fire up Visual Studio, File –> New Project and select Silverlight for Windows Phone –> Windows Phone Application:

image

This sets up the project files and opens up the designer with a design view on the left and the XAML view on the right. For this example let’s create an application that browses the public Netflix catalog here: https://odata.netflix.com/v1/Catalog/ (By the way there are a lot of OData producers and the list is growing. Check them all out here: https://www.odata.org/producers)

Create the Client Proxy and Add the Assembly Reference

I’ve written a lot about OData in the past but I’ve always used clients that take advantage of the full .NET framework like Console apps, WPF apps and Excel add-ins. When you create these projects it’s easy to just add a service reference to the OData service and the client proxy and client assemblies are automatically added to your project. Unfortunately these steps are manual in a Windows Phone 7 project, but it’s not too bad. Here are the steps:

1. Extract the ODataClient_BinariesAndCodeGenToolForWinPhone.zip and unblock the files (Right-click –> Properties –> click the “Unblock” button on the General tab).

image

2. Use the DataSvcUtil.exe contained in here to generate the client proxy. This will generate the client-side classes based on the OData service. So for my example, I’ll open up a command prompt and generate my Netflix classes in the file “NetflixModel.vb” like so:

>datasvcutil /uri:https://odata.netflix.com/v1/Catalog/ /out:.\NetflixModel.vb /Version:2.0 /DataServiceCollection /language:VB

3. Copy the output file to your Windows Phone 7 Project. You can just copy the file from Windows explorer and paste it directly into the project in Visual Studio (I love that feature :-)).

4. In your Windows Phone 7 project, add a reference to the System.Data.Services.Client assembly also contained in the zip you extracted in step 1.

image

Build the Application

Okay now that we have all the pieces in place let’s add some basic UI and some code to call the Netflix OData service. What I’ll do is provide a simple Listbox that lists titles that fall into a genre that the user can type in a textbox. The Title class has a Name property and that’s what we’ll databind our listbox to. Here’s the XAML for my UI contained in the MainPage.xaml:

   <!--ContentPanel - place additional content here-->
        <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="Auto" />
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition Height="*" />
                <RowDefinition Height="Auto" />
            </Grid.RowDefinitions>
            <ListBox Grid.ColumnSpan="2" ItemsSource="{Binding}">
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding Name}" />
                    </DataTemplate>
                </ListBox.ItemTemplate>
            </ListBox>
            <TextBox Name="textBox1" Text="Adventures" Grid.Row="1" />
            <Button Content="Go" Grid.Column="1" Grid.Row="1" Name="button1" />
        </Grid>

image

Titles and Genres participate in a many-to-many relationship so we need to query the Genre based on its name and include the Titles for that Genre. When the user clicks the Go button that’s when I’m going to execute the query. A query against an OData service is just an HTTP GET so we need to construct the right URI to the service. When working with the OData client in full .NET framework, you have the the ability to write LINQ queries and the client library will translate them to http calls. Unfortunately this isn’t supported on the phone yet. (See this announcement on the team blog for details.)

Fortunately it’s pretty easy to construct the URIs.  If you open up your favorite browser to https://odata.netflix.com/v1/Catalog/Genres that will execute a query that returns all the Genres in the Netflix catalog. In order to pull up a specific Genre called “Adventures” we just use https://odata.netflix.com/v1/Catalog/Genres('Adventures') and in order to get the Titles returned for this Genre we use the $expand syntax: https://odata.netflix.com/v1/Catalog/Genres('Adventures')?$expand=Titles (Take a look at the URI conventions for all the operations that are supported.)

Once you have the URI you can call the LoadAsync method to fetch the data. For my application, in order to get an ordered list of titles into the ListBox I execute an in-memory LINQ query over the results to manipulate them further. So here’s the code for the MainPage:

 Imports System.Data.Services.Client
Imports WindowsPhoneApplication1.NetflixCatalog.Model

Partial Public Class MainPage
    Inherits PhoneApplicationPage

    Dim WithEvents ctx As New NetflixCatalog.Model.NetflixCatalog(New Uri("https://odata.netflix.com/v1/Catalog"))
    Dim WithEvents genres As New DataServiceCollection(Of Genre)(ctx)
    Dim titles As IEnumerable(Of Title)

    Public Sub New()
        InitializeComponent()
    End Sub

    Private Sub button1_Click(sender As System.Object,
                              e As System.Windows.RoutedEventArgs) Handles button1.Click

        genres.Clear()
        Dim url = String.Format("/Genres('{0}')?$expand=Titles", Me.textBox1.Text)

        Dim uri = New Uri(url, UriKind.Relative)
        genres.LoadAsync(uri)
    End Sub

    Private Sub genres_LoadCompleted(sender As Object,
                                     e As LoadCompletedEventArgs) Handles genres.LoadCompleted
        If genres.Any Then
            titles = From g In genres
                     From t In g.Titles
                     Select t Distinct
                     Order By t.Name

        Else
            titles = New List(Of Title) From {New Title With {.Name = "No titles found in that genre."}}
        End If

        Me.DataContext = titles
    End Sub
End Class

Run it!

Okay hit F5 and watch the phone emulator fire up. Type in a genre and hit the Go button to see the results loaded from the Netflix Catalog OData service. Sweet!

image

Tips & Tricks

Here’s a couple tips for an easier time when building Windows Phone 7 apps that consume OData services.

Visualize your OData - If you don’t know the schema of the OData service you’re working with it may be kind of hard to visualize the relations between entities. I recommend installing the OData Protocol Visualizer extension and then just add a console application to your Solution in Visual Studio, add a service reference to the OData service to generate the proxy classes, and then right-click on the service reference and select “Show in Diagram”.

image

Using LINQ - The System.Data.Service.Client library for the full .NET framework has the ability to take your LINQ queries and translate them to http calls. If you’re more comfortable with LINQ (like me) you can use the same console application to see how the queries are translated. You can either view the http call by putting a debugger breakpoint on your LINQ queries or you can install Fiddler (which I highly recommend) to see all the http traffic.

So I hope this helps in getting you started with OData on Windows Phone 7. OData is fun and easy and it’s a great way to exchange data over the web in a standard way. Now I just need to brush up on my design “skillz” and see if I can make a prettier looking WP7 app ;-)

Enjoy!