One of the features I love about WCF Data Services are QueryInterceptors. They make previously cumbersome(ish) tasks simple and remove the margin for error.

If you are not familiar with a QueryInterceptor then in a nutshell they enable you to define a query that is applied each time a request is made for a defined entity. The query can filter based on any of the attributes of your entity and are a blessing when applying filtering based on security.

To steal a quote directly from the MSDN help they provide the following:

Entity set-level authorization and validation is implemented by methods annotated with the QueryInterceptorAttribute. WCF Data Servicess do not implement security policies but instead provide the infrastructure required for service developers to write their own security rules and business validation.

So how do you use a QueryInterceptor? Well read on to find out and potentially open your eyes to a whole new way of doing things.

One of the first things I used a QueryInterceptor for was to filter out entities that had been marked as deleted. So for example, if I have an entity called Product and it has a column IsDeleted of type ‘bit’ then I can define the following interceptor:

[QueryInterceptor("Products")] public Expressionbool>> OnQueryProducts() { return lo => lo.IsDeleted false; }

This means that any time I access my exposed Product entity, via the beauty of OData , then the filter above will be automatically applied for me and I will only return results that do not have the IsDeleted flag set to True.

So I can do any OData query I like and I will not have to worry about filtering out Products that are marked as deleted. The QueryInterceptor above will do it for me.

Take these 2 examples for instance:

http://samples.bondigeek.com/services/PagerService.svc/Products?$orderby=ProductName&$filter=ProductId gt 15”

and

http://samples.bondigeek.com/services/PagerService.svc/Products?$orderby=ProductName

Neither one has any mention of a filter on IsDeleted but since the QueryInterceptor is defined at the server level, any call against the Product entity will have the filter applied to it. You can find out more about the pager service referenced above on this previous blog post.

Pretty cool!

Another example of the power of a QueryInterceptor is that of filtering based on Access Levels.

If you are using the asp.net Membership Provider to control access to your entities then you can make use of this to filter out data based on who you are.

The code below first determines who is making the call and then looks up a custom User object to determine what organisation the User belongs to. It then uses that piece of information to filter out the results that are returned to only those that match the organisation that the requesting User belongs to.

[QueryInterceptor("OrganisationUsers")] public Expressionbool>> OnQueryOrganisationUsers() { MembershipUser member = Membership.GetUser(); if (member != null) { using (MyEntities ctx = new (MyEntities ()) { var user = (from ou in ctx.OrganisationUsers where ou.UserId (Guid)member.ProviderUserKey select ou).SingleOrDefault(); if (user != null) { if (user.Organisation.OrganisationTypeId 1) { return lo => lo.OrganisationId user.OrganisationId; } else { return lo => lo.OrganisationId > 0; } } else { thrownew System.Data.EntityException("User not found"); } } } else { thrownew System.Security.Authentication.AuthenticationException("Access Denied"); } }

Hopefully this has given you a good understanding of what a QueryInterceptor is and how it can be applied to your development work if you are utilising WCF Data Services.

BondiGeek