Ranting and raving about anything I feel like complaining about.

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 When you say
"Download the Windows Phone 7 OData Library here" the "here" part seems to be missing.
Gravatar Already fixed it Joe...but thanks!
Gravatar 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 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 Looks like the zip available via the download links is empty. Or is it just me? Either way, thanks for the info.
Gravatar 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 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 Denis,

Most likely your server-side configuration isn't set up to allow writing to the database.
Gravatar What would be the main advantages to consuming an OData endpoint instead of a SOAP endpoint (exposed from RIA services)
Gravatar You mentioned the tooling wasn't there (Add Service Reference) yet. Do you know if it will be in RTW bits?
Gravatar 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 Kevin,

I assume its a bug. I am hoping there is a fix when they rev the library.
Gravatar 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 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 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 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 Its a little confusing as you're treating the result as an object where as Users is a collection.
Gravatar 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 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 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 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 Shawn, thanks for this. I just confirmed that this info continues to work fine for the release build of WP7.
Gravatar 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

Add a Comment

*
*
*