Cache me if you can

22 בנובמבר 2007

תגיות: ,
3 תגובות

 

WCF provides nice capability of extending the behavior of operations by implementing IOperationBehavior interface. I want to concentrate on ApplyDispatchBehavior method of that interface, which purpose is to do extention to server side calls. I will show how I use this extensability to provide a nice and easy cache mechanisam.

I will make a class which derives from Attribute class and implements an IOperationBehavior interface. Now I want to interfire in the invoke process of the method so I need to make another class that implements IOperationInvoker interface and would hold the cache logic. And then set it to dispatch.Invoker property of the ApplyDispatchBehavior method. Let see some code:

class CacheMeAttribute: Attribute, IOperationBehavior
{
    #region IOperationBehavior Members
    public void ApplyDispatchBehavior(OperationDescription description, DispatchOperation dispatch)
    {
        dispatch.Invoker = new CommonInvoker(dispatch.Invoker);
    }
    //other interface methods.
    
    #endregion
} 
class CommonInvoker : IOperationInvoker
{
    public Cache AppCache
    {
        get
        {
            return HttpRuntime.Cache; 
        }
    }

    IOperationInvoker BaseInvoker;
        
    public CommonInvoker(IOperationInvoker baseInvoker)
    {
        this.BaseInvoker = baseInvoker;
    }
        
    
    #region IOperationInvoker Members

    public object[] AllocateInputs()
    {
        object[] ret = this.BaseInvoker.AllocateInputs();
        return ret;
    }

    public object Invoke(object instance, object[] inputs, out object[] outputs)
    {
        string key = GetCacheKey(inputs);
        object result = AppCache[key];
        if (result == null)
        {
            result = this.BaseInvoker.Invoke(instance, inputs, out outputs);
            AppCache[key] = result;
        }
        outputs = new object[0];
        return result;
     }

     // other interface methods.

      #endregion

    private string GetCacheKey(object[] inputs)
    {
        string key = string.Empty;
        for (int i = 0; i < inputs.Length; i++)
             key += inputs[0].ToString();
        return key;
    }
}

The cache algorithm is shown in the Invoke method and cache the return value of the calling method by the parameters given to the method input. I use HttpRuntime.Cache for the caching and it work well for both win and web application as I explained in my last post.

Now all you have to do in order to cache data is add CacheMe attribute over a method like this:

[ServiceContract(Namespace = "Dobkin.Services")]
interface IMyService
{
    [OperationContract]
    string Mult(int x, int y);
}

class MyService : IMyService
{
    [CacheMe]
    public long Mult(int x, int y)
    {
        return x * y;
    }
} 

And that's it. Now every time that Mult method will be called then the CommonInvoker will check if there is entry in the cache with a 'xy' key. If there is, the value will be returned to the caller without executing the method.

See full example of the code here.

הוסף תגובה
facebook linkedin twitter email

כתיבת תגובה

האימייל לא יוצג באתר. (*) שדות חובה מסומנים

3 תגובות

  1. rrfrqrmq10 בינואר 2008 ב 21:25

    bkkrvybk http://yxniaoaw.com yhawxilp okcrtfzy [URL=http://hzwookrw.com]mcwvabrf[/URL] zcsticqv

    להגיב
  2. Ronnie11 בנובמבר 2008 ב 12:26

    This is a great post, Nati, and it was very useful for other things besides caching. One word of caution though for anyone who reuses the CommonInvoker class though–the Invoke() method sets the out parameters to an empty array, which will not work if any of your WCF operations use out params, and there's nothing in the cache for a response.

    להגיב
  3. David11 במרץ 2009 ב 13:17

    With your key construction, if you call the service to multiple 36 x 2, and then again to multiple 3 x 62, won't it tell you that 3 x 62 = 72?

    להגיב