Using OData with Windows Phone 7 SDK Beta

Url: http://wildermuth.com/downloads/wp7odatamovies.zip

Windows Phone 7

While I was giving my OData talk, someone asked about consuming OData on the WP7 phone. I had done this on the CTP earlier, but hadn't tried it during the beta. So I figured I'd look into it today. While this is still pretty easy to do, the tooling still isn't in place. This means that you can't simply do an "Add Service Reference" to a Windows Phone 7 project. Instead you have to follow these steps:

  • Download the Windows Phone 7 OData Library here.
  • Unzip the Windows Phone 7 OData Library to get access to the reference.
  • In your project, add a reference to the System.Data.Services.Client.dll assembly from the .zip file.
  • Create the proxy classes by using the .NET 4.0's DataSvcUtil.exe (located in the %windir%\Microsoft.NET\Framework\v4.0.30319 directory). See the example below:
%windir%\Microsoft.NET\Framework\v4.0.30319\DataSvcUtil.exe 
   /uri:http://odata.netflix.com/Catalog/ 
   /out:NetflixModel.cs
   /Version:2.0
   /DataServiceCollection
  • Include this new proxy class (containing the context object and the data classes) in your WP7 application.
  • Use the class to call out to the service as necessary:
NetflixCatalog ctx = 
  new NetflixCatalog(new Uri("http://odata.netflix.com/Catalog/"));

var qry = from p in ctx.People
                        .Expand("TitlesDirected")
          where p.Name == "Stanley Kubrick"
          select p;
      
// Create DataService query since we're not 
// using a DataServiceCollection
var dsQry = (DataServiceQuery<Person>)qry;

dsQry.BeginExecute(r =>
  {
    try
    {
      var result = dsQry.EndExecute(r).FirstOrDefault();
      if (result != null)
      {
        Deployment.Current.Dispatcher.BeginInvoke(() =>
          {
            Titles = result.TitlesDirected;
          });
      }
    }
    catch (Exception ex)
    {
      MessageBox.Show(ex.Message);
    }
  }, null);

Note that you need to use a Dispatcher as this call is *not* guaranteed to be called on the UI thread.  This was the one piece that was unexpected.  Once I marshaled the update to the UI thread, all worked perfectly.

Here's the example: download

 

 

Comments

Gravatar

Joe Healy Monday, August 09, 2010

When you say
"Download the Windows Phone 7 OData Library here" the "here" part seems to be missing.

Gravatar

Shawn Wildermuth Monday, August 09, 2010

Already fixed it Joe...but thanks!

Gravatar

Glen Gordon Tuesday, August 10, 2010

Shawn, do you have any insight into the relative performance for the various ways one could consume data from the web in a Phone application? I've heard that OData is kind of expensive in terms of serialization/deserialization. Certainly if one is consuming a data source where that's the only option, it makes sense to use it, but if one is in control of both the client and server, there are better choices. Any thoughts?

Gravatar

Shawn Wildermuth Tuesday, August 10, 2010

As far as cost of serialization, the cost is about the same for WCF or RIA Services. They were all within 1% of each other in perf tests on the desktop. Hard to tell if on the phone it would be much different.

Gravatar

Bryan Bass Tuesday, August 10, 2010

Looks like the zip available via the download links is empty. Or is it just me? Either way, thanks for the info.

Gravatar

Shawn Wildermuth Tuesday, August 10, 2010

Bryan,

Should be fixed now...but you may need to clear your cache or use a different browser so it actually downloads the new file.

Gravatar

Denis Tuesday, August 10, 2010

Hello Shawn,
i have a problem with adding new entity using OData
private void SaveNewProduct()
{
MyEntities context = new MyEntities(new Uri("http://127.0.0.1:85/MyDataService.svc/"));

try
{
context.AddToProducts(newproduct);
context.BeginSaveChanges(SaveNewProduct_Completed, context);
}
catch (DataServiceRequestException ex)
{
throw new Exception("An error occurred when saving changes.", ex);
}
}

private void SaveNewProduct_Completed(IAsyncResult result)
{
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
MyEntities context = result.AsyncState as MyEntities;
DataServiceResponse response = context.EndSaveChanges(result);
});

}
EndSaveChanges throws the NotSupportedException http://www.screencast.com/users/Shevch_Den/folders/Jing/media/19ad507c-0c86-4c56-8572-84e2e895b1d5.
Do you have any idea how to fix it?


Gravatar

Shawn Wildermuth Tuesday, August 10, 2010

Denis,

Most likely your server-side configuration isn't set up to allow writing to the database.

Gravatar

Kevin Thursday, August 12, 2010

What would be the main advantages to consuming an OData endpoint instead of a SOAP endpoint (exposed from RIA services)

Gravatar

shaggygi Thursday, August 12, 2010

You mentioned the tooling wasn't there (Add Service Reference) yet. Do you know if it will be in RTW bits?

Gravatar

Kevin Meiresonne Friday, August 20, 2010

Hello Shawn,

Any idea why the query fails when I replace the constants with variables? I get a MethodAccessException. Works fine on full Silverlight client.

var qry = from p in ctx.People .Expand("TitlesDirected/Genres")
.Expand("TitlesDirected/Languages")
where p.Name == director // director is variable instead of const string
select p;

Any idea how this can be done?

Gravatar

Shawn Wildermuth Friday, August 20, 2010

Kevin,

I assume its a bug. I am hoping there is a fix when they rev the library.

Gravatar

Kevin Meiresonne Friday, August 20, 2010

Hi Shawn,

I was able to work around it using CreateQuery and AddQueryOption:
var qry = ctx.CreateQuery<People>("People").Expand("TitlesDirected/Genres").Expand("TitlesDirected/Languages").AddQueryOption("Name", director);

Not as pretty, but with some extension methods it can be made strongly typed as well.

Still expect them to fix it though.

Gravatar

Shawn Wildermuth Friday, August 20, 2010

Kevin,

I've reported it to the OData guys for you. Hopefully it will get fixed sooner rather than later. You could make it simpler though and just take your original query and add the query option.

Gravatar

Michael Washington Sunday, August 22, 2010

Ok this is too funny and I had to share it with you.

I am working on a LightSwitch article and trying to get it to Print. you can use a button but if you try to do say a "MessageBox.Show("Hello World!")" you get the obvious thread execution error.

LightSwitch does provide a method to show a MessageBox but of course I'm really trying to show a Print Dialog.

Anyway, I decided to just look at the articles on SilverlightCream and I clicked on yours. then staring me right in the face was "Deployment.Current.Dispatcher.BeginInvoke"...

Gravatar

Scott Sunday, August 29, 2010

Hi Shawn,

I am working through this example but using an Azure oData enabled database. The proxy class created fine, but I am getting two errors in the code below. First, on the Begin Invoke ("cannot convert lambda expression to system.delegate") and second on the result.name ("Cannot implicitly convert type 'string' to 'System.Collections.ObjectModel.ObservableCollection<TechBioModel.User>").
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
Users = result.Name;
});

I was able to bring in the NetflixModel.cs and get that to work so I'm not sure where mine is going wrong. Everything else looks the same. Thanks.

Gravatar

Shawn Wildermuth Sunday, August 29, 2010

Its a little confusing as you're treating the result as an object where as Users is a collection.

Gravatar

Jose Fajardo Monday, August 30, 2010

Just letting people know that the latest SDK for RIA Services exposes ODATA as

http://[SERVER]/[NAMESPACE]-[TYPENAME].svc/ODATA/

The "odata" at the end is important if you want datasvcutil to pick it up otherwise you get the dreaded "404" error page not found!

Gravatar

Shawn Wildermuth Monday, August 30, 2010

Why that is technically true, they don't expose much of the spec except read-only entities; no relationships or full, rich queries. As they've said, the OData support is a "down-payment on OData integration".

Gravatar

Scott Wednesday, September 01, 2010

Hi Shawn, per your comment above I realized my mistake and fixed that, but I am getting the error: An Error Occurred while processing this request on the line:

result = dsQry.EndExecute(r).FirstOrDefault();

What is interesting is that as I step through your code, the Expression property of qry also states "Could not evaluate expression" but nothing is thrown when it executes on the line above. However, in my code, an error is thrown. I have looked at this all evening and can't find where the difference is. My query is a standard LINQ query as well:

var qry = from u in context.Users.Expand("Docs")
where u.ID == 113
select u;

I can't imagine this is an oData or LINQ error since both sets of code see the same Expression error, but I'm not sure why mine would catch it and yours not. What magic did you work on yours? :-)

Thanks...

Gravatar

Shawn Wildermuth Wednesday, September 01, 2010

Scott,

I don't know why its happening exactly. Have you looked at the conversion to URI syntax and see if that works natively?

Gravatar

Scott Seely Thursday, September 16, 2010

Shawn, thanks for this. I just confirmed that this info continues to work fine for the release build of WP7.

Gravatar

Chris Woodruff Thursday, October 28, 2010

Shawn --

With today's new updates to the OData WP7 client library your code is no longer valid. Just a heads up that people may start asking why it does not work.

Woody


Leave a Comment

*
*
*