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
	}


Bookmark and Share

                             

1 Comment

Comments have been disabled for this content.