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;
}