Silverlight and ADO.NET Data Service Operations

Silverlight Logo

In building my Silverlight RC example using ADO.NET Data Services for Entity Framework and NHibernate I ran into what I think is a common pattern.  I am writing an editor for XBox game data. The model for this data uses decorator tables in the database which are modeled as a common "Product" class and derived "Game", "Console" and "Accessory" classes.  In the application I am using paging to only look at fifty results at once. This works fine on both sides. 

But one of the pieces of information I wanted was a list of all the Game Genre.  This became problematic as ADO.NET Data Services wanted me to retrieve all 880 games in order to get a list of these Genres (of which there are only 20 some odd). The whole idea of using paging is go avoid the huge overhead of bringing down the whole entity. Interestingly when I executed a LINQ query that used projection into non-entities, the query wasn't supported as projection isn't allowed in the ADO.NET Data Services URI model (which the client uses).

What ADO.NET Data Services does allow is to create Service Operations (e.g. WebGet or WebInvoke) on the Data Service to extend the model for specific cases. There are some limitations (must return IEnumerable<T>, IQueryable<T> or void) but this works pretty well. The difference between returning IEnumerable and IQueryable is whether system queries can be applied to them.  Returning a fixed list (my need) meant to return a IEnumerable<T> list. Intersting that ADO.NET Data Services support returning an IEnumerable<T> of primitive types.  For example my operation was spec'd as:

[WebGet]
public IEnumerable<string> Genres()
{
}

This works and returns a simple XML file with the primitive values.  But alas the Silverlight Data Service Client doesn't support non-entities. I tried using the DataServiceContext.BeginExecute() to call this service and it threw an exception that it couldn't materialize non-entity classes. Hrmph!

This was a case where adding a quick web service call to get this data on the server and return it would have been the easy road, but that's not how I roll, is it?

After confirming this behavior with the Data team, I decided to write an extension to the DataServiceContext class to support this.  In this little piece of code, the same pattern of calling DataServiceContext.BeginXXX is used. To make this work I simply use the HttpWebRequest class to do a simple GET to the server's URI syntax and use LINQ to XML to convert the data into the simple types (String in my case).

I've started to help out with some new ideas on the CodePlex SilverlightContrib project so I thought this was the perfect place for this code.  Its not packaged up yet in a build (and probably won't be until sometime after RTW ships) but if you want to grab it you can grab the latest checkin I made:

SilverlightContrib ChangeSet 41005

I'll be shipping this new demo as soon as RTW ships (its not done yet). Look for the announcement here.

Comments:

Gravatar

I have no experience with Data Services, but work with WCF all the time. Are you saying that you cannot have IEnumerable<string> as your response contract, but you should instead have IEnumerable<Genre> as your response contract?

While this may seem appropriate from a structured-contract/doing-it-the-right-way sort of way, do you know the reason for the technical limitation?

Gravatar

I'm exploring options for data access in Silverlight 2 and contrasting traditional WCF and Data Services. I get why you'd want to return a non-entity using REST, but in this case it seems like you'd just change your EDM and add a Genre entity.

The example I'm thinking of is more or less to return aggregate results for existing entities without returning the entire graph. For example http://localhost/MyService.svc/TotalSalesYTD might return the Sum of Sales.Amount for the current calendar/fiscal year or ideally http://localhost/MyService.svc/TotalSales?$filter=City%20eq%20'London' would return the Total Sales for customers in London and I could add additional criteria in the URI to specify a date range.

Does my last example make sense and is this something I could implement using your Contrib as a starting point?

Thanks for the post (and feedback).

Greg

Gravatar

This is great code you provided here Shawn - fitting exactly what I have found missing in the ado.net data services. I found myself lost in all kind of xml parsing (syndicates etc) of the extended service operations. But your SilverlightContrib.Data.Services.dll is great.

Will source be released at codeplex or somewhere else ?

Im sure the (former) astoria datateam would consider this functionality for their future release of ado.net data services as integral part.

One last Q: What would you recommend using: Entity model OR NHibernate (considering all aspects - e.g. maturity, maintenance, learning courve developers, performance etc) for building mid/large scale line-of-businness silverlight apps ?

Gravatar

I found answer to my first Q:
SilverlightContrib ChangeSet 41005
:-)

Gravatar

TS,

The Entity Framework vs. NHibernate isn't the story. ADO.NET Data Services supports LINQ providers so it should work with any LINQ-based providers (LLBLGen Pro is another one). The right ORM is based on a number of factors and I would be negligent if I simply said one is better than the other. Its not that simple.

Gravatar

Horses for courses.

We've used LLBLGen for several years, we have an investment in our existing technology built on top of it and the team's understanding of the API. For this reason we wont' be considering entity framework.

From what I can see Microsoft have gone to some effort to follow the provider pattern with their new technologies (MVC, Dynamic Data, Ado.NEt Data Services), so the choice is yours...

As an aside I just ported Shawns example Silverlight app accessing Northwind via an ADO.NEt data service / Entity Framework to LLBLGen (using a third party LLBLGen tool), and it works well, with some minor modifications of the code




Gravatar

Matthew,

Great to see a LLBLGen version. As you see, I think the magic here is that any DAL that has LINQ will work. If you want to send it to me, i'll add it to the list of providers and show all three providers in the example!


 



 
Save Cancel