Friday, 24 July 2009

Select Filter for ADO.NET Data Services

UPDATE 2 Sept 2009: Microsoft have now released CTP2 of ADO.NET Data Services, which now supports projections. You'd be crazy to use my solution now, so I've removed it from CodePlex. You can download CTP2 from here: http://blogs.msdn.com/astoriateam/archive/2009/08/31/ado-net-data-services-v1-5-ctp2-now-available-for-download.aspx Anthony.

If you want to build a service layer for your app in a flash, ADO .NET Data Services is the bee’s knees in my opinion. That said, being a new technology there are a few shortfalls I’ve come across.

The first is a lack of support for retrieving a count of records, which is a must if you intend to do paging of data. Thankfully, Microsoft has released a v1.5 CTP which addresses this (see my previous blog post).

The second glaring omission is the inability to only return selected properties from an entity in a query. This is otherwise known as projection, but I think of it as a traditional SELECT statement in SQL. Currently, a Data Service will always return all properties of all entities (or in my SQL analogy, SELECT *).

When you remember that you’re sending all data over HTTP from the server to the client, this can have a massive performance impact as you are almost always retrieving way more data than you need.

No way José! I’m sure Microsoft is well aware of this and are beavering away on a great solution, but in the meantime I’ve come up with a very dodgy, but equally effective solution in the form of a Http Module.

Download Select Filter for ADO.NET Data Services

After spending considerable time fiddling with Query Interceptors in my data services, there really is no way to only return selected properties from an entity. The only workaround at a code level would be to create custom entities that only have the properties you need – but that ‘aint pretty.

So I ended up using more of a “brute force” solution, by letting the Data Service do its thing, but then intercepting the Http response before it’s sent back to the client. By creating a custom Http Module, I was able to catch the response, remove the unwanted properties, and then stream the modified response to the client.

Note #1: I’m not using the ADO .NET Data Service Client libraries to consume my services, I call the services directly using AJAX. If you’re using the client libraries through Silverlight etc, I doubt this solution will be any good for you.

Note #2: My solution only works with JSON responses at the moment, as this is all I use. However it would be very easy to add support for XML if required.

Here’s how to get up and running:

  1. Download the library and add a reference to AntsCode.DataServiceSelect.dll in your Data Services project.
  2. Add the following HttpModule to your Web.config:
<httpModules>
    <add name="DataServiceModule" type="AntsCode.DataServiceSelect.DataServiceModule"/>
</httpModules>
That’s it really. Now, when you make a data service request, you can add a new select parameter, specifying the properties to return:

http://yourserver.com/YourService.svc/Customers?select=FirstName,LastName

The HttpModule will intercept the response, and filter out unwanted properties:

{
    d: [
    {
        “FirstName”: “John”,
        “LastName”: “Bloggs”
    },
    {
        “FirstName”: “Anne”,
        “LastName”: “Jones”
    }
]}

How is the data filtered? While I could have deserialized the JSON response into an object, and somehow removed the unwanted properties programmatically; I instead opted to use regular expressions and just strip out the unwanted text as I felt this would be much more efficient (I told you the solution was dodgy!!) You can see this in action in the DataServiceJsonFilter class in the source code.

Of course I’m really hanging out for an update from Microsoft to do this properly, at which point I’ll promptly throw this code in the bin. In the meantime, if you have any feedback or bugs, please report them on the CodePlex site.

Anthony.