OData WCF Data Services Query Interceptor Example

We can intercept HTTP GET requests to WCF Data Services to add some custom business logic to an operation. We do this by decorating a method with a specific Query Interceptor attribute within the DataService derived class. Essentially it is a predicate added to the query for the request. This way we can filter data based on some business rules on each GET request.

In the example below we restrict OData queries for Hotels to only the top rated ones with 5 stars. We do this by configuring a Query Interceptor for the Hotels entity in HotelService.svc.

using System;
using System.Data.Services;
using System.Linq.Expressions;
using Remondo.Entities;
 
namespace HotelDataService
{
    public class HotelService : DataService<HotelEntities>
    {
        public static void InitializeService(DataServiceConfiguration config)
        {
            config.SetEntitySetAccessRule("Hotels", EntitySetRights.AllRead);
        }
 
        [QueryInterceptor("Hotels")]
        public Expression<Func<Hotel, bool>> OnQueryOrders()
        {
            return hotel => hotel.Stars == 5;
        }
    }
}

Now the AtomPub result set only contains the top rated hotels if we query for http://[servername]/HotelService.svc/Hotels

<?xml version="1.0" encoding="iso-8859-1" standalone="yes"?>
 
<feed xml:base="http://localhost:10013/HotelService.svc/" 
      xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" 
      xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" 
      xmlns="http://www.w3.org/2005/Atom">
  
  <title type="text">Hotels</title>
  <id>http://localhost:10013/HotelService.svc/Hotels/</id>
  <updated>2012-04-16T18:39:17Z</updated>
  <link rel="self" title="Hotels" href="Hotels" />
  <entry>
    <id>http://localhost:10013/HotelService.svc/Hotels(4)</id>
    <title type="text"></title>
    <updated>2012-04-16T18:39:17Z</updated>
    <author>
      <name />
    </author>
    <link rel="edit" title="Hotel" href="Hotels(4)" />
    <category term="RemondoModel.Hotel" 
              scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
    <content type="application/xml">
      <m:properties>
        <d:ID m:type="Edm.Int32">4</d:ID>
        <d:Name>The Roosevelt Hotel</d:Name>
        <d:City_ID m:type="Edm.Int32">1</d:City_ID>
        <d:Stars m:type="Edm.Int32">5</d:Stars>
      </m:properties>
    </content>
  </entry>
  <entry>
    <id>http://localhost:10013/HotelService.svc/Hotels(5)</id>
    <title type="text"></title>
    <updated>2012-04-16T18:39:17Z</updated>
    <author>
      <name />
    </author>
    <link rel="edit" title="Hotel" href="Hotels(5)" />
    <category term="RemondoModel.Hotel" 
              scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
    <content type="application/xml">
      <m:properties>
        <d:ID m:type="Edm.Int32">5</d:ID>
        <d:Name>Hotel de L'Europe</d:Name>
        <d:City_ID m:type="Edm.Int32">2</d:City_ID>
        <d:Stars m:type="Edm.Int32">5</d:Stars>
      </m:properties>
    </content>
  </entry>
</feed>

If we query for an existing hotel by ID with a lower rating than 5, we get a resource not found error. http://[servername]/HotelService.svc/Hotels(3)

<?xml version="1.0" encoding="iso-8859-1" standalone="yes"?>
 
<error xmlns="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
  <code></code>
  <message xml:lang="nl-NL">Resource not found for the segment 'Hotels'.
  </message>
</error>

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>