CachingCallHandler and Unity 2.0
Unity 2.0 no longer includes CachingCallHandler, as you can see in here. Since this is something I use very often, I decided to bring it back, with some changes:
- It no longer uses ASP.NET cache, but the new MemoryCache
- The current process is part of the cache key
- The full method signature is included as part of the key, not just it's name
Otherwise, it is based on the source code from Enterprise Library 4.1.
[Serializable] [ConfigurationElementType(typeof(CustomCallHandlerData))] [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)] public sealed class CachingCallHandlerAttribute : HandlerAttribute, ICallHandler { #region Private fields private readonly Guid KeyGuid = new Guid("ECFD1B0F-0CBA-4AA1-89A0-179B636381CA"); private TimeSpan expirationTime = new TimeSpan(0, 5, 0); #endregion #region Public Constructors public CachingCallHandlerAttribute() { } public CachingCallHandlerAttribute(Int32 hours, Int32 minutes, Int32 seconds) { this.expirationTime = new TimeSpan(hours, minutes, seconds); } #endregion #region Public override methods public override ICallHandler CreateHandler(IUnityContainer ignored) { return (this); } #endregion #region ICallHandler Members public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext) { if (this.targetMethodReturnsVoid(input) == true) { return (getNext()(input, getNext)); } Object [] inputs = new Object [ input.Inputs.Count ]; for (Int32 i = 0; i < inputs.Length; ++i) { inputs [ i ] = input.Inputs [ i ]; } String cacheKey = this.createCacheKey(input.MethodBase, inputs); ObjectCache cache = MemoryCache.Default; Object [] cachedResult = (Object []) cache.Get(cacheKey); if (cachedResult == null) { IMethodReturn realReturn = getNext()(input, getNext); if (realReturn.Exception == null) { this.addToCache(cacheKey, realReturn.ReturnValue); } return (realReturn); } IMethodReturn cachedReturn = input.CreateMethodReturn(cachedResult [ 0 ], input.Arguments); return (cachedReturn); } #endregion #region Private methods private Boolean targetMethodReturnsVoid(IMethodInvocation input) { MethodInfo targetMethod = input.MethodBase as MethodInfo; return ((targetMethod != null) && (targetMethod.ReturnType == typeof(void))); } private void addToCache(String key, Object value) { ObjectCache cache = MemoryCache.Default; Object [] cacheValue = new Object [] { value }; cache.Add(key, cacheValue, DateTime.Now + this.expirationTime); } private String createCacheKey(MethodBase method, params Object [] inputs) { StringBuilder sb = new StringBuilder(); sb.AppendFormat("{0}:", Process.GetCurrentProcess().Id); sb.AppendFormat("{0}:", KeyGuid); if (method.DeclaringType != null) { sb.Append(method.DeclaringType.FullName); } sb.Append(':'); sb.Append(method); if (inputs != null) { foreach (Object input in inputs) { sb.Append(':'); if (input != null) { sb.Append(input.GetHashCode().ToString()); } } } return (sb.ToString()); } #endregion }