OData is a great concept, it provides the strongly-typed data formats of SOAP-based services, with the low payload highly flexible REST-based services. It also brings its own twists such as URL based operators to allow for SQL-like querying, sorting, and filtering. This lightweight data protocol has seen great adoption through both Microsoft, and non-Microsoft based products on both the client, and server and also throughout popular sites such as Netflix, eBay, and StackOverflow.
The construct and design of the OData protocol lend it to also be a great solution for mobile application development and Microsoft have even created client SDKs and code generator tools for all of the major mobile platforms, including their very own Windows Phone 7. The use of OData on Windows Phone is however very much a confusing story at this points in time. The Windows Phone API, as you more than likely know is built upon the .NET Compact Framework running a cut down version of Silverlight. Due to this it does not have fully fledging support for the .NET framework and thus has caused some issues with the OData API’s being ported across. If you fired up Visual Studio and created a new ASP.NET application to access OData you can simply use the built-in Add Service Reference code generator (or via the command line DataSvcUtil.exe) and you’ll automatically be presented with strongly typed entities (in the same fashion as a SOAP-based service) and a fluent LINQ-style data context you can use for data entry. Unfortunately within Windows Phone 7 development we don’t have these luxuries (yet) which has meant guides to using the OData client are misleading and sometimes even wrong (this is because early CTPs and beta’s of the WP7 client SDK where different to the released version). So I’d like to take some time out to create a basic demo and show you how easy(ish) it is to get up and running with OData on Windows Phone 7.\
Getting Set-up with MVVM Light
So open up Visual Studio and create a new Windows Phone 7 Silverlight project (if you don’t have this template you can download it from here).
Once you have done that we need to create our framework skeleton for our phone application. As this is a Silverlight project we are going to use Model View ViewModel (MVVM), and currently I prefer the MVVMLight framework. So I’m going to add this in using Nuget.
Once MVVMLight has installed itself, you’ll notice it would have created a ViewModel folder, and added two classes MainViewModel.cs and ViewModelLocator.cs. We’ll need to wire these up to our application, so first open up App.xaml and add the following code:
<Application.Resources> <!--Global View Model Locator--> <vm:ViewModelLocator x:Key="Locator" d:IsDataSource="True" /></Application.Resources>
Then open up the code behind (AppCode.xaml.cs) and add the following:
private void Application_Launching(object sender, LaunchingEventArgs e){ DispatcherHelper.Initialize();}
You will also need to add the namespace for the ViewModel (vm) :
xmlns:vm="clr-namespace:ODataApplication.ViewModel"
Next you need to wire up the ViewModel to to the View, so open up MainPage.xaml and add the following to the phone:phoneApplication node:
DataContext="{Binding Main, Source={StaticResource Locator}}"
Getting OData
So now we have our MVVM framework wired up, we need to somehow get our data plugged in. First create a directory within your projet called Service, this is where we will keep the OData classes. Nexy we need to download the OData Windows Phone 7 client SDK. You’ll find this on CodePlex here. There are a few different flavours of the download, but the one you want is ODataClient_BinariesAndCodeGenToolForWinPhone.zip which contains both the necessary assemblies and also a customised version of the Code Generator DataSvcUtil.exe for use with the WP7 Silverlight runtimes .
Once downloaded, add both System.Data.Services.Client.dll and System.Data.Services.Design.dll as references to your project (remember to unblock the assemblies first).
Next open up a command prompt, and set a path to the location of where your downloaded copy of DataSvcUtil.exe is located. Now change the path to your location of your Visual Studio project, and the Service directory you just created. From the command prompt run DataSvcUtil.exe, which takes the following arguments:
/in:<file> The file to read the conceptual model from
/out:<file> The file to write the generated object layer to/language:CSharp Generate code using the C# language
/language:VB Generate code using the VB language
/Version:1.0 Accept CSDL documents tagged with m:DataServiceVersion=1.0 or lower
/Version:2.0 Accept CSDL documents tagged with m:DataServiceVersion=2.0 or lower
/DataServiceCollection Generate collections derived from DataServiceCollection
/uri:<URL> The URI to read the conceptual model from
/help Display the usage message (short form: /?)
/nologo Suppress copyright message
We are going to use the following combination (NB: for this example we are using the NetFlix OData Service):
datasvcutil /uri:http://odata.netflix.com/Catalog /out:Model.cs /version:2.0 /DataServiceCollection
You will see the application execute, and it should complete with no errors or warnings.
Now open up Visual Studio, and click the show hidden files icon, find the newly created file (Model.cs) and include it in your solution.
Using OData Models
The file that was just created actually contains multiple objects, including a data context for accessing data and also model representations of the OData entities. As we used the /DataServiceCollection prefix all of our models have been created to support the INotifyPropertyChanged interface so we can actually exposes them all the way through to our View. So what we’ll do next is set-up the data binding between the Model –> ViewModel –> View. Open up your ViewModel (MainViewModel.cs) and create the following property:
private ObservableCollection<Genre> _genres; public ObservableCollection<Genre> Genres{ get { return _genres; } set { _genres = value; RaisePropertyChanged("Genres"); }}
Next (for simplicity) we’ll wire-up this property to the MainPage.xaml file using a ListBox that will repeat for each genre that is retrieved from the Netflix service and list the name out in a text block. Here is the XAML we need to implement:
<!--ContentPanel - place additional content here--><Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"> <ListBox ItemsSource="{Binding Genres, Mode=OneWay}"> <ListBox.ItemTemplate> <DataTemplate> <TextBlock Text="{Binding Name, Mode=OneWay}" /> </DataTemplate> </ListBox.ItemTemplate> </ListBox></Grid>
Connecting OData EndPoint to a ViewModel
The last thing we need to do in our project is to populate our ViewModel with data. To do this we are going to create a new class within our Service directory, called NetflixServiceAgent.cs. For simplicity we’ll create a single method called GetGenres(Action<ObservableCollection<Genre>> sucess) which takes a single argument of an async Action to pass back data to our ViewModel. Populate the method with the following code:
public void GetGenres(Action<ObservableCollection<Genre>> success){ var ctx = new NetflixCatalog.Model.NetflixCatalog(new Uri("http://odata.netflix.com/Catalog/")); var collection = new DataServiceCollection<Genre>(ctx); collection.LoadCompleted += (s, e) => { if (e.Error != null) { throw e.Error; } else { if (collection.Continuation != null) { collection.LoadNextPartialSetAsync(); } else { success(collection); } } }; collection.LoadAsync(new Uri(@"Genres/", UriKind.Relative));}
What we are doing here is creating a new data context, which acts as an aggregate handling all of the interaction with the OData Service. Next we create a new DataServiceCollection (of the type of the Entity model we wish to return) and pass in the context to it’s constructor. DataSericeCollection is actually derived from ObservableCollection (the Collection type we use in Silverlight databinding) but it also contains methods to synchronous and asynch data retrieval as well as continuation where by the OData service is handling pagination. As with everything in Silverlight we are using the asynchronous data retrieval mechanism, and we pass in an anonymous method to the event handler which ensures an error has not been returned and then returns the collection. The actual LoadAsync method accepts an argument of type URI. This URI should be relative to the one we’ve already passed into the data context, and is representative of the both the entity and query we want to return. This is the primative form of the fluent-LINQ API we have in the full .NET framework, so for instance if we wanted to apply filters to the OData query we would change the URI to reflect this, such as “Genres/$skip=1&$top5”.
Once we have created our service agent, our final task to get us up and running is to call it from within the ViewModel. So open up MainViewModel.cs and within the constructor add the following:
var repo = new NetFlixServiceAgent();repo.GetGenres((success) => DispatcherHelper.CheckBeginInvokeOnUI(() => { Genres = success; }));
And that’s it. By running the application we’ll see the not-so overly fancy list of genres being populated from the OData Service.
Over the next few weeks I’ll upload some more posts around OData clients and WCF Data Services to try and expand on this example so more.
This was 6 months ago, when I first started looking into this project. My aim was to convince someone to fund the prototype, so I could show case the experience at conferences – but unfortunately I failed . So it was much to my surprise when earlier this week CNN announced (