This project is read-only.

Client Side Caching Decorator/Advice Needed

Jan 8, 2015 at 7:55 PM
Hi,

First of all, thanks again for your product.

We currently have a massive WCF service (those that have 100+ operations and the service and contract is split into partial classes) that's running in production. It is however very solid and there's not much wrong with it's design.

Our client-side code, however, is littered with Proxy "using"'s and memory cache usage (like the bad example below)
var returnValue;
using (var proxy = new WcfProxy<IMyService>
{

   if (!cache.Contains(key))
   {
   ... do something and set the value in the cache
   } else {
      ... set returnvalue to cache value
   }
  
}
I'm sure you get the idea... unfortunately.

What I've implemented thus far to clean-up a huge portion of our client (web and Windows Forms) code is the below. My Cache is injected into my code quite easilly as I have an ICacheProvider (currently I have a MemoryCacheProvide and NullCacheProvider)

Based on the bloat in the client projects this would be an extremely easy win and allow us to improve things further in the future.
public interface IServiceCallHelper
    {
        ServiceResponse<T> MakeServiceCall<T>(Func<IMyService, T> serviceMethod);

        Task<ServiceResponse<T>> MakeAsyncServiceCall<T>(Func<IMyService, T> serviceMethod);
    }
The actual implementation is then responsible for managing the proxy connection and my usage ends up being :
return serviceCallHelper.MakeAsyncCall(x => x.UpdateUser(user));
Because my service helper implements an interface I thought it would be a breeze to implement a caching decorator. I did just that and registered it with no problem. Debug the project, works out of the box.

I then created a custom attribute to put on the methods I'd like to cache (trust me there's so many that simply just ignoring caching is a very bad place to be).

Problem, because I pass FUNC through, I have no data on the actual method and the parameter values for it. So, I changed it to Expression<Func> but I'm not getting any further.

I've investigated the following alternatives :
  1. Rewrite the clients :) Lol. no...
  2. Use an interceptor with Castle Dynamic Proxy (starting to feel a bit dirty) and besides, your product doesn't cater for interception out of the box.
  3. Create overloaded methods in my helper to allow for cache region and interval and inject my cache provider. Possible, should only be a few lines of added code but would require guys to add a key value.
Ideally I'd like the key value to be Method-<ParameterList> (purely to stick to historical conventions) and be completely hidden from them. There is a difference between GetUser(1) and GetUser(2) as an example.

Any advice would greatly be appreciated.
Jan 8, 2015 at 8:48 PM
Hi, by the looks of things you've made pretty sure there's no quick win here.

See here for out-of-the-box support for interception and here for a variation that uses Castle. Also see here for something else that may help.
Jan 9, 2015 at 4:15 AM
From your description it seems unlikely to me that your application applies the SOLID principles correctly. Having a big WCF service with many interfaces is an example of an Interface Segregation Principle violation.

Although using interception might give you some quick wins, for the long run, I would advise to improve your application design in a way that removes many of the troubles you're currently ha b ing. What comes to mind is applying the command/handler and query/handler patterns as described here https://www.cuttingedge.it/blogs/steven/pivot/entry.php?id=91 and here https://www.cuttingedge.it/blogs/steven/pivot/entry.php?id=92. These patterns allow you to have a very small and maintainable WCF service as described here: https://www.cuttingedge.it/blogs/steven/pivot/entry.php?id=95. Furthermore, those patterns make it easy and clea to apply decorators instead of interceptors, which leads to cleaner and more maintainable code.