Use AppFabric Cache to cache your WCF Service response
[This post has been updated to support InvokeBegin and InvokeEnd to support BizTalk Receive Locations]
We’ve just finished the “BizTalk Release Party” in Stockholm, where Stephen W. Thomas, Richard Seroter and Ewan Fairweather held some fantastic sessions. One of the talks was about the AppFabric Cache formally known as “Velocity”.
Whenever I come across a new technology I try to put it in some useful context, where I can try it out. This is usually a quite painful process, as I tend to do this long before the technology has reached any sort of mature state. AppFabric Cache is a v1 product and therefore considerable more stable then other products or technologies I’ve been experimenting with.
While Ewan was presenting the Windows Server AppFabric Cache I though it could be interesting to use it for caching outgoing WCF service responses, so that the back-end logic would not be executed if it was cached. I’m not sure how useful this scenario really is, but I guess there could be many scenarios where it would be ok not to get the latest version of the information. Some of those situations might be:
- Where the information is accessed during office hours, and only updated through nightly batches.
- Where a composite service get bursts of calls that would often be the same.
- When services expose static data which will seldom change over time.
In my sample I’ll use a fictitious Weather Forecast Service, which I think would qualify as good candidate because:
- Nobody trust the weather forecasts in the first place, so it doesn’t matter if the result not 100% up to date.
- The service is frequently called with the same input parameters (Zip code).
- The service will support a very popular
IPhone Windows 7 Mobile application, which in turn will cause an immense load on our back-end systems.
How it works:
|WCF: The incoming call from the client is received through the Transport channel, after which it will proceed through an encoder and possible some other channels before it reaches the Dispatcher. |
The Dispatcher is the last step before the request is handed over to the actual service. The Dispatcher is responsible for associating the incoming call with the appropriate operation and then invoking it.
By creating a custom OperationInvoker you may customize the behavior of how the back-end logic is invoked.
Windows Server AppFabric Cache provides distributed caching over many servers. It can utilize a cluster of servers that communicate with each other to form a single, unified application cache system. It comes with a decent API, and can be managed using PowerShell.
The Visual Studio solution has three projects:
|Project ||Description |
|bLogical.CachingExtension ||This is the main project, responsible for the custom behavior. |
|bLogical.WcfWeatherService ||A WCF service application, applying the CacheOperationBehavior attribute to indicate the response of the method should be cached if possible. The service makes a call to a database to pickup the forecast. |
|bLogical.Client ||Client tool calling the two services. |
The cache implementation:
Using the Windows Server AppFabric Cache is pretty straight forward. I recommend you read Scott Hanselman’s post on the subject. The post also covers the installation process.
Basically you use the DataCashe.Put method to add the data to the cache, and the DataCache.Get method to retrieve the cached value. Working with the Windows Server AppFabric Cache is similar to using a HashTable, where you add values along with a key (string) which you can later use to get the value back.
public object Invoke(object instance, object inputs, out object outputs)
// Serialize all input parameters. The string will be used as the Key to the Cache.
string input = GetSerializedKey(inputs);
// Return value from the Method
object value= this._cacheHelper.Cache.Get(input);
if (value != null)
outputs = new object;
//Invoke the method
value = this._innerOperationInvoker.Invoke(instance, inputs, out outputs);
// Add the return value to the Cache.
this._cacheHelper.Cache.Put(input, value, new TimeSpan(0,0,0,0,this._timeOut));
I use the input parameters as Key. But as the parameters can be any number of objects, I need to serialize them into an XML string first. I can then use the string as key together with the result from the invoked method. As I don’t want the value to be cached forever, I also pass in a TimeSpan to indicate the lifetime of the cached object.
Using the caching behavior:
You can use the cache behavior either declaratively in your code:
public interface IWeatherForecastService
Forecast GetForecast(string zipCode);
…or through configuration:
<cachingBehavior timeout="00:10:00" cacheName="bLogical"/>
Version=184.108.40.206, Culture=neutral, PublicKeyToken=49c05550fea0c875"/>
I’ve run two tests; One with and one without caching enabled. I haven’t got time to run this in any real test environment. But even though I’ve run the test on my local laptop, the tests came out pretty clear.
Without Caching (~3 calls/sec):
(Using Visual Studio profiler, I found the database call to take ~200ms)
With Caching (~23 calls/sec):
Download and install:
1. Download the Windows Server AppFabric.
2. Read Scott Hanselman’s post as to how to set it up.
3. Open PowerShell and run the following commands:
get-command -module DistributedCacheConfiguration
First you need to grant access to your service account:
Grant-CacheAllowedClientAccount [Your Account]
Continue to create the Cache:
Start the cluster:
4. Download the sample
Using it with BizTalk:
Follow these steps to use the bLogical.CachingExtensions with BizTalk:
- Add a key to the bLogical.CachingExtensions project.
- Build the project and add it to the GAC.
- Open machine.config and add the extension to the behaviorExtensions section.
- Open BizTalk Administration Console
- Add a Request/Response ReceivePort > Add a Location
- Set the transport to WCF-Custom, and click configure
- Set the URI and Binding.
- On the Behavior tab, add a ServiceBehavior and select the CacheElement: