Last active
February 20, 2019 19:43
-
-
Save miklund/5802719 to your computer and use it in GitHub Desktop.
A simple cache interceptor using Castle.DynamicProxy2.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace LiteMedia.Cache | |
{ | |
public static class CacheArg<T> | |
{ | |
public static readonly T Any = default(T); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace LiteMedia.Cache | |
{ | |
using System; | |
using System.Collections.Generic; | |
using System.ComponentModel.Composition; | |
using System.Linq; | |
using System.Linq.Expressions; | |
using System.Reflection; | |
using System.Runtime.Caching; | |
using Castle.DynamicProxy; | |
[Serializable] | |
[Export] | |
public class CacheInterceptor<T> : IInterceptor, IDisposable | |
{ | |
[NonSerialized] | |
private readonly MemoryCache cache; | |
private readonly List<MethodInfo> cacheDirectory; | |
private bool disposed; | |
public CacheInterceptor() | |
{ | |
cache = new MemoryCache(GetType().Name); | |
cacheDirectory = new List<MethodInfo>(); | |
} | |
~CacheInterceptor() | |
{ | |
Dispose(false); | |
} | |
public void Cache(Expression<Func<T, object>> target) | |
{ | |
if (target == null) | |
{ | |
throw new ArgumentNullException("target", "You're trying to watch null for cached values. Are you stupid?"); | |
} | |
MethodCallExpression expression = null; | |
if (target.Body is UnaryExpression) | |
{ | |
expression = ((UnaryExpression)target.Body).Operand as MethodCallExpression; | |
} | |
expression = expression ?? target.Body as MethodCallExpression; | |
if (expression == null) | |
{ | |
throw new InvalidOperationException("Unable to get method info from expression."); | |
} | |
cacheDirectory.Add(expression.Method); | |
} | |
public void Intercept(IInvocation invocation) | |
{ | |
if (invocation == null) | |
{ | |
throw new ArgumentNullException("invocation", "It is highly unlikely that you're trying to intercept on a null instance since that would give you compile time errors. But what the heck! You might be doing something really inventive."); | |
} | |
if (cacheDirectory.Contains(invocation.Method)) | |
{ | |
var key = invocation.Arguments.Aggregate(string.Empty, (acc, item) => acc + item); | |
if (cache.Contains(key)) | |
{ | |
invocation.ReturnValue = cache[key]; | |
} | |
else | |
{ | |
invocation.Proceed(); | |
cache.Add(key, invocation.ReturnValue, DateTime.UtcNow.AddDays(1)); | |
} | |
} | |
else | |
{ | |
invocation.Proceed(); | |
} | |
} | |
public void Dispose() | |
{ | |
Dispose(true); | |
GC.SuppressFinalize(this); | |
} | |
private void Dispose(bool disposing) | |
{ | |
if (!disposed) | |
{ | |
if (disposing) | |
{ | |
// managed resources | |
} | |
// unmanaged resources | |
cache.Dispose(); | |
} | |
disposed = true; | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace LiteMedia.Cache | |
{ | |
using Castle.DynamicProxy; | |
public static class CastleExtensions | |
{ | |
public static T InterceptWith<T>(this T target, IInterceptor interceptor) | |
where T : class | |
{ | |
// no interceptor - return target as is | |
if (interceptor == null) | |
{ | |
return target; | |
} | |
var factory = new Castle.DynamicProxy.ProxyGenerator(); | |
return factory.CreateInterfaceProxyWithTarget(target, interceptor); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment