Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I implement a UpdateCallback on a CacheItemPolicy from another class?

I have a simple Cache attribute implemented using postsharp. When I set the cache policy I want to be able to set a update callback like below.

 private static CacheItemPolicy GetCachePolicy(CacheType type, int expiry)
    {
        var policy = new CacheItemPolicy();

        switch (type)
        {
            case (CacheType.Absolute):
                policy.AbsoluteExpiration = DateTimeOffset.Now.AddSeconds(expiry);
                policy.UpdateCallback = new CacheEntryUpdateCallback(UpdateHandler);
                break;
            case (CacheType.Sliding):
                policy.SlidingExpiration = new TimeSpan(0, 0, 0, expiry);
                break;
        }

        return policy;
    }

This is fine if I just want to do this:

 private static void UpdateHandler(CacheEntryUpdateArguments arguments)
    {
        throw new NotImplementedException();
    }

However, I want to be able to pass in a delegate/method/ method name and parameters into dynamically and execute that. SO I would expect to see something like (obviously syntax is wrong):

private static CacheItemPolicy GetCachePolicy(CacheType type, int expiry Func<?,?> method)
    {
        var policy = new CacheItemPolicy();

        switch (type)
        {
            case (CacheType.Absolute):
                policy.AbsoluteExpiration = DateTimeOffset.Now.AddSeconds(expiry);
                policy.UpdateCallback = new CacheEntryUpdateCallback(method);
                break;
            case (CacheType.Sliding):
                policy.SlidingExpiration = new TimeSpan(0, 0, 0, expiry);
                break;
        }

        return policy;
    }

**********UPDATE********

I got it working. Not the most elegant method, bud it works.

My Aspect code is as follows:

[Serializable]
public sealed class CacheAttribute : MethodInterceptionAspect
{
    private readonly CacheType m_cacheType;
    private readonly int m_expiry;
    private readonly bool m_useCallBack;
    private KeyBuilder m_keyBuilder;

    public KeyBuilder KeyBuilder
    {

        get { return m_keyBuilder ?? (m_keyBuilder = new KeyBuilder()); }

    }

    public CacheAttribute(CacheType cacheType, int expiry, bool useCallBack)
    {
        m_cacheType = cacheType;
        m_expiry = expiry;
        m_useCallBack = useCallBack;
    }

    public CacheAttribute(CacheType cacheType, int expiry)
    {
        m_cacheType = cacheType;
        m_expiry = expiry;
        m_useCallBack = false;
    }


    //Method executed at build time.

    public override void CompileTimeInitialize(MethodBase method, AspectInfo aspectInfo)
    {

        KeyBuilder.MethodParameters = method.GetParameters();

        KeyBuilder.MethodName = string.Format("{0}.{1}", method.DeclaringType.FullName, method.Name);

    }

    public override void OnInvoke(MethodInterceptionArgs context)
    {
        object value;


        string key = KeyBuilder.BuildCacheKey(context, context.Arguments);
        if (!CacheHelper.Get(key, out value))
        {
            // Do lookup based on caller's logic. 
            context.Proceed();
            value = context.ReturnValue;
            var cacheObject = new CacheObject {CacheValue = value, Context = context};
            CacheHelper.Add(cacheObject, key, m_cacheType, m_expiry, m_useCallBack);
        }

        context.ReturnValue = value;
    }
}

My Callback is as follows:

  private static void UpdateHandler(CacheEntryUpdateArguments arguments)
    {
        CacheObject cacheObject = (CacheObject)arguments.Source.Get(arguments.Key);
        cacheObject.Context.Proceed();
        cacheObject.CacheValue = cacheObject.Context.ReturnValue;

        CacheItem updatedItem = new CacheItem(arguments.Key, cacheObject);
        arguments.UpdatedCacheItem = updatedItem;
    }
like image 669
Lee Cook Avatar asked Sep 17 '11 09:09

Lee Cook


2 Answers

You can do this:

private static CacheItemPolicy GetCachePolicy(CacheType type, int expiry, 
                                    Action<CacheEntryUpdateArguments> method)
{
     ...
     policy.UpdateCallback = (a) => method(a);
     ...
     return policy;
}

Or just this:

private static CacheItemPolicy GetCachePolicy(CacheType type, int expiry, 
                                             CacheEntryUpdateCallback method)
{
     ...
     policy.UpdateCallback = method;
     ...
     return policy;
}
like image 153
TheCodeKing Avatar answered Nov 17 '22 00:11

TheCodeKing


I think you can do this

`
    private static CacheItemPolicy GetCachePolicy(CacheType type, int expiry, Func method)
    {
        var policy = new CacheItemPolicy();

        switch (type)
        {
            case (CacheType.Absolute):
                    Action updateCallBackHandler = null;
                    updateCallBackHandler = delegate(CacheEntryUpdateArguments arguments)
                    {                         
                        var newData = FetchYourDataWithCustomParameters();

                        arguments.UpdatedCacheItem = new CacheItem(arguments.Key, newData);
                        arguments.UpdatedCacheItemPolicy = new CacheItemPolicy()
                        {
                            AbsoluteExpiration = DateTimeOffset.Now.AddSeconds(expiry),
                            UpdateCallback = new CacheEntryUpdateCallback(updateCallBackHandler)
                        };
                    };

                    policy.UpdateCallback = new CacheEntryUpdateCallback(updateCallBackHandler);

                break;
            case (CacheType.Sliding):
                policy.SlidingExpiration = new TimeSpan(0, 0, 0, expiry);
                break;
        }

        return policy;
    }
'
like image 40
Hai Vu Avatar answered Nov 17 '22 01:11

Hai Vu