Using Expressions in WCF

Most business applications deal with showing, analyzing and modifying some kind of business relevant data. Although it is not a rare thing that customers ask you to “load everything” into a grid and let them work the data like they “always did in Excel” this is rarely a good idea. As soon as you have more than “Hello World!” numbers of records in your persistent storage, loading that data will take time, network bandwidth, CPU cycles for (de)serialization and disk I/O etc. pp.

A much better approach is to limit the number of records to be returned as early as possible by filtering out those records that don’t match your criteria. In a client/server application that means doing the filtering on the server. If you use WCF for the communication between client and server there is a slight glitch you need to work around: How do you get the filtering criteria to the server?

Out of the box you can’t transmit the Expression trees that represent your queries over the wire. They are not serializable. Using strings is tedious and prone to typos. In addition you will have to parse your query string unless you use some vendor specific format like Hibernate’s HQL which adds vulnerabilities like “xQL injection” to the mix. Creating server side methods for each filter you can think of is inflexible (i.e. users can’t create dynamic queries) and will result in a lot of code for something that is as easy as a one-line expression would be. Using some implementation of the Specification pattern would also require you to write quite some amount of code for the different search criteria which would only duplicate a subset of the features that Expressions offer. In addition you would add yet another syntax that your co-developers need to master. So unless you don’t mind to write, test, fix, document, update and maintain a lot of code you are back to square one.

Serialize.Linq to the rescue

The problem of Expressions not being serializable is as old as LINQ itself. This article on MSDN dates as far back as 2008. The author uses XML to represent the original query. Another article in a recent edition of a German .NET magazine uses a custom IQueryProvider that performs the translation between Expression tree and XML. Both implementations work to a certain degree but I have to admit I like neither one. My personal opinion on XML: It’s one huge PITA to work with. Sorry for the language. So I try to avoid having to deal with it whenever possible.

Serialize.Linq works a bit different: It maps each node of the original expression tree to a node that the DataContractSerializer can easily digest (I know that means XML somewhere under the covers, but the chances that I will ever see it or have to deal with it are close to zero). In a WCF scenario, this structure is then serialized, transmitted over the wire, deserialized into Serialize.Linq’s custom node format and from there back to a real Expression tree. You can find some articles that describe features of the framework on Sascha Kiefer’s blog.

This article talks about using Serialize.Linq together with WCF. It’s easy and requires almost zero work on your side. You just have to do the conversion between Expressions and SL’s ExpressionNodes whenever you query for data. Over and over again. Hm… Wouldn’t it be a lot better if I could save that effort as well?

I think I got the idea from various posts on Oren Eini’s blog: If you have repetitive tasks that are always the same put them into your infrastructure to relieve the burden on the developers a little. Well, considering that my infrastructure in this case is WCF which has about a bazillion extension points and that I have some experience with messing with WCF’s serialization behavior from my experiments with Enumeration classes I thought I would give it a shot.

Yet another IDataContractSurrogate

I found out that I can reuse most of the code I wrote for the custom serialization of Enumeration classes. By replacing Enumerations with Expressions I got it working in almost no time on the server side. The code snippets ignore methods that are not implemented for brevity.

public class SerializeExpressionsBehavior : Attribute, IServiceBehavior, IContractBehavior, IWsdlExportExtension
{
  private readonly ExpressionDataContractSurrogate surrogate;
  public SerializeExpressionsBehavior()
  {
    this.surrogate = new ExpressionDataContractSurrogate();
  }
  void IServiceBehavior.ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase host)
  {
    foreach (ServiceEndpoint endpoint in serviceDescription.Endpoints)
    {
      foreach (OperationDescription operation in endpoint.Contract.Operations)
      {
        DataContractSerializerOperationBehavior behavior = operation.Behaviors.Find();
        if (behavior == null)
        {
          behavior = new DataContractSerializerOperationBehavior(operation) { DataContractSurrogate = this.surrogate };
          operation.Behaviors.Add(behavior);
        }
        else
        {
          behavior.DataContractSurrogate = this.surrogate;
        }
      }
    }
    this.HideEnumerationClassesFromMetadata(host);
  }
  private void HideEnumerationClassesFromMetadata(ServiceHostBase host)
  {
    ServiceMetadataBehavior smb = host.Description.Behaviors.Find();
    if (smb == null)
    {
      return;
    }
    WsdlExporter exporter = smb.MetadataExporter as WsdlExporter;
    if (exporter == null)
    {
      return;
    }
    object dataContractExporter;
    XsdDataContractExporter xsdInventoryExporter;
    if (!exporter.State.TryGetValue(typeof(XsdDataContractExporter), out dataContractExporter))
    {
      xsdInventoryExporter = new XsdDataContractExporter(exporter.GeneratedXmlSchemas);
    }
    else
    {
      xsdInventoryExporter = (XsdDataContractExporter)dataContractExporter;
    }
    exporter.State.Add(typeof(XsdDataContractExporter), xsdInventoryExporter);
    if (xsdInventoryExporter.Options == null)
    {
      xsdInventoryExporter.Options = new ExportOptions();
    }
    xsdInventoryExporter.Options.DataContractSurrogate = this.surrogate;
  }
}

And the DataContractSurrogate that performs the actual translation between Expressions and ExpressionNodes.

public class ExpressionDataContractSurrogate : IDataContractSurrogate
{
  public Type GetDataContractType(Type type)
  {
    if (typeof(Expression).IsAssignableFrom(type))
    {
      return typeof(ExpressionNode);
    }
    return type;
  }
  public object GetObjectToSerialize(object obj, Type targetType)
  {
    Expression expression = obj as Expression;
    if (expression != null)
    {
      return expression.ToExpressionNode();
    }
    return obj;
  }
  public object GetDeserializedObject(object obj, Type targetType)
  {
    if (typeof(Expression).IsAssignableFrom(targetType))
    {
      return ((ExpressionNode)obj).ToExpression();
    }
    return obj;
  }
}

As I wanted to use Expressions on the client side as well I needed a new EndpointBehavior to hook up the surrogate. After that … it just worked 🙂

public class ClientSideSerializeExpressionsBehavior : IEndpointBehavior
{
  private IDataContractSurrogate surrogate;
  public ClientSideSerializeExpressionsBehavior()
  {
    this.surrogate = new ExpressionDataContractSurrogate();
  }
  public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
  {
    foreach (OperationDescription operation in endpoint.Contract.Operations)
    {
      DataContractSerializerOperationBehavior behavior = operation.Behaviors.Find();
      if (behavior == null)
      {
        behavior = new DataContractSerializerOperationBehavior(operation) { DataContractSurrogate = this.surrogate };
        operation.Behaviors.Add(behavior);
      }
      else
      {
        behavior.DataContractSurrogate = this.surrogate;
      }
    }
  }
}

So far I tested my solution with proxies derived from ClientBase<T>

using (var proxy = new MyServiceClient(new BasicHttpBinding(), new EndpointAddress(ServiceAddress)))
{
  Customer[] customers = proxy.QueryCustomers(c => c.Id > 3);
  // ...
}

(the client side behavior is added in the proxies constructor)

public MyServiceClient(Binding binding, EndpointAddress address)
  : base(binding, address)
{
  this.Endpoint.Behaviors.Add(new ClientSideSerializeExpressionsBehavior());
}

and those generated on-the-fly by a ChannelFactory<T>. Works like a charm 🙂

var factory = new ChannelFactory(new BasicHttpBinding(), ServiceAddress);
factory.Endpoint.Behaviors.Add(new ClientSideSerializeExpressionsBehavior());
var proxy = factory.CreateChannel();
Customer[] customers = proxy.QueryCustomers(c => c.Id > 3);

What you get and what’s missing

What you get is this beauty:

var customers = proxy.QueryCustomers(c => c.Id > 3);

Neat and simple.

With Serialize.Linq and the small additions to the WCF infrastructure outlined above you can use Expressions when querying a WCF service without breaking your workflow by manually translating queries to another format. Just use the same queries that you would use for any other data source. Done.

I have yet to evaluate wether the above code works with clients generated using “Add service reference”. But that will be the topic of another article. What’s definitely not working is seamlessly using Expressions in Silverlight clients. DataContractSurrogates are among the features that MS decided not to support in Silverlight. *sigh*

As usual you can grab the code from my page on CodePlex (projects TecX.Expressions and TecX.Expressions.Test). Enjoy! 🙂

Transparently Caching Queries

The How and the What are often discussed when it comes to caching. As always, there is no Silver Bullet that solves all issues at once.

TecX offers one solution for the following scenario: Say you have a datasource that provides access to your data via a set of IQueryable<T> properties. The interface might look like this:

public interface ICustomerRepository
{
  IQueryable<Customer> Customers { get; }
}

Now you want to add caching but you don’t want to have to change how the consumers work with that repository. So you need some transparent caching mechanism that isolates your consumers (and your developers) from the actual implementation of caching. You are then able to run your application without caching or you can use the new features from System.Runtime.Caching, the AppFabric Cache or something completely different.

Two classes from TecX.Caching (namely QueryInterceptor and QueryInterceptorProvider) allow for transparent interception of queries against an IQueryable<T>. They are wrappers for IQueryable and IQueryProvider that use the Expression property of the IQueryable to generate a unique cache key. A simple ToString() operation won’t give you a key that is “uniqe enough” so a technique presented by Pete Montgomery is used to partially evaluate the expression tree of the query.

The sample CachingCustomerRepository demonstrates how this interception can be used to introduce a transparent caching layer into your application and swap it out for arbitrary implementations using different caching technologies at any time.

public class CachingCustomerRepository : ICustomerRepository
{
  private readonly ICustomerRepository inner;
  private readonly ObjectCache cache;
  private readonly QueryInterceptor<Customer> customers;
  private readonly ExpirationToken expirationToken;
  public CachingCustomerRepository(ICustomerRepository inner)
  {
    this.inner = inner;
    this.cache = new MemoryCache(typeof(CachingCustomerRepository).Name);
    this.customers = new QueryInterceptor<Customer>(this.inner.Customers);
    this.customers.QueryProvider.Executing += this.OnQueryExecuting;
    this.customers.QueryProvider.Executed += this.OnQueryExecuted;
    this.expirationToken = new ExpirationToken();
  }
  public IQueryable<Customer> Customers { get { return this.customers; } }
  public void Add(Customer customer)
  {
    this.inner.Add(customer);
    this.expirationToken.Expire();
  }
  private void OnQueryExecuted(object sender, ExpressionExecuteEventArgs e)
  {
    IQueryable<Customer> cachedResult = this.cache[e.CacheKey] as IQueryable<Customer>;
    if (cachedResult == null)
    {
      var evaluatedQueryable = ((IEnumerable<Customer>)e.Result).ToList().AsQueryable();
      CacheItem cacheItem = new CacheItem(e.CacheKey, evaluatedQueryable);
      CacheItemPolicy policy = new CacheItemPolicy { SlidingExpiration = 1.Minutes() };
      ExternallyControlledChangeMonitor monitor = new ExternallyControlledChangeMonitor
        {
          ExpirationToken = this.expirationToken
        };
      policy.ChangeMonitors.Add(monitor);
      this.cache.Add(cacheItem, policy);
    }
  }
  private void OnQueryExecuting(object sender, ExpressionExecuteEventArgs e)
  {
    IQueryable<Customer> cachedResult = this.cache[e.CacheKey] as IQueryable<Customer>;
    if (cachedResult != null)
    {
      e.Handled = true;
      e.Result = cachedResult;
    }
  }
}

Using a framework like Moq you can easily mock your actual data access in order to run tests against your cache.

var mock = new Mock<ICustomerRepository>();
mock.SetupGet(r => r.Customers).Returns(
new[]
{
  new Customer { Id = 1, Name = "1" },
  new Customer { Id = 2, Name = "2" },
  new Customer { Id = 3, Name = "3" }
}.AsQueryable());
var cache = new CachingCustomerRepository(mock.Object);

// Actual testing code

mock.VerifyGet(r => r.Customers, Times.Once());

At the heart of the CachingCustomerRepository are the QueryInterceptor (comes in a generic and a non-generic version)

public class QueryInterceptor<T> : QueryInterceptor, IQueryable<T>
{
  public QueryInterceptor(IQueryable<T> wrapped)
    : this(wrapped, new QueryInterceptorProvider(wrapped.Provider))
  {
  }
  public QueryInterceptor(IQueryable<T> wrapped, QueryInterceptorProvider provider)
    : base(wrapped, provider)
  {
  }
  public IEnumerator<T> GetEnumerator()
  {
    var enumerable = this.Provider.Execute<IEnumerable<T>>(this.Expression);
    var enumerator = enumerable.GetEnumerator();
    return enumerator;
  }
}
public class QueryInterceptor : IQueryable
{
  private readonly IQueryable wrapped;
  private readonly QueryInterceptorProvider queryProvider;
  public QueryInterceptor(IQueryable wrapped, QueryInterceptorProvider provider)
  {
    this.wrapped = wrapped;
    this.queryProvider = provider;
  }
  public Type ElementType { get { return this.wrapped.ElementType; } }
  public Expression Expression { get { return this.wrapped.Expression; } }
  public IQueryProvider Provider { get { return this.queryProvider; } }
  public QueryInterceptorProvider QueryProvider { get { return this.queryProvider; } }
  IEnumerator IEnumerable.GetEnumerator()
  {
    var enumerable = (IEnumerable)this.Provider.Execute(this.Expression);
    var enumerator = enumerable.GetEnumerator();
    return enumerator;
  }
}

and the QueryInterceptorProvider.

public class QueryInterceptorProvider : IQueryProvider
{
  private readonly IQueryProvider wrapped;
  public QueryInterceptorProvider(IQueryProvider wrapped)
  {
    this.wrapped = wrapped;
  }
  public event EventHandler<ExpressionExecuteEventArgs> Executing = delegate { };
  public event EventHandler<ExpressionExecuteEventArgs> Executed = delegate { };
  public IQueryable<TElement> CreateQuery<TElement>(Expression expression)
  {
    var rawQuery = this.wrapped.CreateQuery<TElement>(expression);
    var interceptor = new QueryInterceptor<TElement>(rawQuery, this);
    return interceptor;
  }
  public IQueryable CreateQuery(Expression expression)
  {
    var rawQuery = this.wrapped.CreateQuery(expression);
    var interceptor = new QueryInterceptor(rawQuery, this);
    return interceptor;
  }
  public TResult Execute<TResult>(Expression expression)
  {
    string cacheKey = expression.GetCacheKey();
    object value;
    bool handled = this.NotifyExecuting(expression, cacheKey, out value);
    TResult result = !handled ? this.wrapped.Execute<TResult>(expression) : (TResult)value;
    this.NotifyExecuted(expression, cacheKey, result);
    return result;
  }
  public object Execute(Expression expression)
  {
    string cacheKey = expression.GetCacheKey();
    object value;
    bool handled = this.NotifyExecuting(expression, cacheKey, out value);
    object result = !handled ? this.wrapped.Execute(expression) : value;
    this.NotifyExecuted(expression, cacheKey, result);
    return result;
  }
  private bool NotifyExecuting(Expression expression, string cacheKey, out object result)
  {
    var e = new ExpressionExecuteEventArgs
      {
        Expression = expression,
        CacheKey = cacheKey
      };
    this.Executing(this, e);
    if (e.Handled)
    {
      result = e.Result;
      return true;
    }
    result = null;
    return false;
  }
  private void NotifyExecuted(Expression expression, string cacheKey, object result)
  {
    var e = new ExpressionExecuteEventArgs
      {
        Expression = expression,
        CacheKey = cacheKey,
        Result = result
      };
    this.Executed(this, e);
   }
}

The code above illustrates one possible solution for one problem: How can I introduce a completely transparent caching layer around my data access?

Explicit caching on the contrary allows you to optimize what you put in the cache and when. This video by the guys behind StackOverflow shows which performance improvements and hardware savings are possible when you make caching very explicit.

Whenever you introduce caching to your application there are some questions that need to be answered:

  • Do I really have to cache every query?
  • Can I reuse parts of my results?
  • Will I run this exact query often enough to justify caching?
  • What happens when data changes (e.g. by calling UpdateCustomer)?
  • How much does performance really improve by introducing caching?
  • Does caching have an influence on the consistency of my results?

Don’t use caching if you can’t reason that the benefits outweigh the costs. Caching can cause a lot of trouble if it’s not done the right way…

Get the source code for transparent caching here (project TecX.Caching and the test suite that shows how to use it in TecX.Caching.Test).