Thursday, November 4, 2010

WCF Data Services - Reflection Provider

A colleague and I have spent some time lately exploring and finally implementing a WCF Data Service.  In a nut shell this is a service interface to expose a data model over a service boundary using Linq.  Exposing a data model over a service boundary is not that special, anyone can write a service that returns an array of objects and maybe some methods that take some criteria arguments allowing return of filtered objects.  What makes this special is the fact you access the data using Linq (with some obscure and advanced Linq features disabled). Linq allows a familar means of data access from the client's point of view, and out of the box provides a huge range of data filtering, grouping, paginating and lazy loading features.

So what is this "Reflection Provider" flavour of WCF Data Services? Other providers include "Entity Framework Provider" for exposing a EF model over the wire, and "Custom Provider"; see MSDN for more details.  The reflection provider works by pointing it at a class that defines a series of properties that return IQueryable.  This exposes all the sets your data model contains.  Each individual type can relate to other types in the model but each type must have a set property defined.  The beauty about this is most of the time you have an existing object model that can be exposed, all you need is a basic class to expose the IQueryable sets.

Obviously it would be easier to use Entity Framework, but in the problem I'm working on, there is no database, just a pre-loaded in memory object graph.  Exposing it to allow querying was pretty straight forward (with a few gotchas), and enabling editing of the object model is possible too.

Here's a sample application I wrote based on extending the example on MSDN,
Basic Example.

Here's a few gotcha's that my colleague and I found along the way:

  • Every type must have a DataServiceKeyAttribute. This must point to a unique "primary-key" property on the type.
  • References to sets, ie, the many side of a one to many relationship should be of type IList<T>.
  • Enums do not get shipped across the wire for some reason. There are plenty of requests on the forums to cater for this, hopefully will appear in a future release. This can be worked around by ignoring this property and having an equivelent int property. Use the IgnorePropertyAttribute to exclude a property. On the client side the enum can be partialled back in.
  • Don't forget to use the Linq Expand method to instruct WCF to return related sets of data, by default these get excluded.

Next I had a look at performance.  I compared it to a standard WCF service where you would have to write your own methods to provide ways of returning a sensible amount of data.  Seems like a crazy comparison to do I know, but it was necessary to prove a point.  Its pretty obvious that if you choose not to use WCF Data Services you will end up writing your own query language in the form of many OperationContracts. Using Linq is far less work and a huge amount of flexibility out of the box.

The long and short of it is Linq is actually faster due to a standard service is always going to return populated (eager) related sets. This means potentially huge graphs of data being served back when the client only will use one object.  You would be able to code a way to return only the object requested but its extra work and very proprietry and extra code to debug.

Thanks Marjorie for your input, great work!

1 comment:

  1. Apologies for those having difficulty using the download link. I've moved the files to skydrive which will make it easier to download.