Business Logic Toolkit for .NET
www.bltoolkit.net
Welcome Guest, you are in: Login
|  Home   |  Download   |  Documentation   |  Discussions   |  Issues   |  License   |
RSS RSS

Navigation




Search the wiki
»

PoweredBy
This aspect helps to cache method calls. The aspect uses input method parameters to create a cache key and caches return value and all output (both ref and out) parameters. By default only value types and string type of the method parameters are used to create a cache key. Any other types are ignored. This behavior can be changed by assigning the CacheAspect.IsCacheableParameterType property to a delegate providing custom logic.

CacheAspect.cs

using System;
using System.Reflection;

using NUnit.Framework;

using BLToolkit.Aspects; using BLToolkit.Reflection;

namespace HowTo.Aspects { public abstract class TestClass { public static int Value;

// This is a method we will cache. Cached return value depends on input parameters. // We will change the 'Value' field outside of the class and see how it affects the result. // [Cache(MaxCacheTime=500, IsWeak=false)] public virtual int CachedMethod(int p1, int p2) { return Value; }

public static TestClass CreateInstance() { // Use TypeAccessor to create an instance of an abstract class. // return TypeAccessor<TestClass>.CreateInstance(); } }

[TestFixture] public class CacheAspectTest { [Test] public void Test1() { TestClass tc = TestClass.CreateInstance();

DateTime begin = DateTime.Now;

// Initial setup for the test static variable. // TestClass.Value = 777;

while (tc.CachedMethod(2, 2) == 777) { // This change will not affect the Test method return value for 500 ms. // TestClass.Value++; }

double totalMilliseconds = (DateTime.Now - begin).TotalMilliseconds;

Assert.GreaterOrEqual(totalMilliseconds, 500); }

[Test] public void Test2() { TestClass tc = TestClass.CreateInstance();

// Return value depends on parameter values. // TestClass.Value = 1; Assert.AreEqual(1, tc.CachedMethod(1, 1)); TestClass.Value = 2; Assert.AreEqual(1, tc.CachedMethod(1, 1)); // no change TestClass.Value = 3; Assert.AreEqual(3, tc.CachedMethod(2, 1));

// However we can clear cache manually. // For particular method: // CacheAspect.ClearCache(typeof(TestClass), "CachedMethod", typeof(int), typeof(int)); TestClass.Value = 4; Assert.AreEqual(4, tc.CachedMethod(2, 1));

// By MethodInfo: // MethodInfo methodInfo = tc.GetType().GetMethod("CachedMethod", new Type[] { typeof(int), typeof(int) }); CacheAspect.ClearCache(methodInfo); TestClass.Value = 5; Assert.AreEqual(5, tc.CachedMethod(2, 1));

// For the all cached methods. // CacheAspect.ClearCache(); TestClass.Value = 6; Assert.AreEqual(6, tc.CachedMethod(2, 1)); } } }

If we decompile the actual emitted TestClass class, we may see something like the following:

[BLToolkitGenerated]
public sealed class TestClass : HowTo.Aspects.TestClass
{
    private static CallMethodInfo _methodInfo;
    private static IInterceptor   _interceptor;

public override int CachedMethod(int p1, int p2) { int returnValue = 0;

if (_methodInfo == null) { _methodInfo = new CallMethodInfo((MethodInfo)MethodBase.GetCurrentMethod()); }

InterceptCallInfo info = new InterceptCallInfo();

info.Object = this; info.CallMethodInfo = _methodInfo; info.ParameterValues[0] = p1; info.ParameterValues[1] = p2; info.ReturnValue = returnValue; info.InterceptResult = InterceptResult.Continue; info.InterceptType = InterceptType.BeforeCall;

if (_interceptor == null) { _interceptor = new CacheAspect(); _interceptor.Init(_methodInfo, "MaxCacheTime=500;IsWeak=False"); }

// 'BeforeCall' step checks if the method is cached. // If it is and the cache is not expired, the Intercept method populates // return value and output parameters with the cached values and // sets info.InterceptResult to InterceptResult.Return. // See the [link][file]Aspects/CacheAspect.cs[/file]CacheAspect.BeforeCall[/link] method for details. // _interceptor.Intercept(info);

returnValue = (int)info.ReturnValue;

if (info.InterceptResult != InterceptResult.Return) { // If the method call is not cached, target method is called. // returnValue = base.CachedMethod(p1, p2);

info.ReturnValue = returnValue; info.InterceptResult = InterceptResult.Continue; info.InterceptType = InterceptType.AfterCall;

// 'AfterCall' step stores parameters and return values in the cache. // See the [link][file]Aspects/CacheAspect.cs[/file]CacheAspect.AfterCall[/link] method for details. // _interceptor.Intercept(info);

returnValue = (int)info.ReturnValue; }

return returnValue; } }
© 2010 www.bltoolkit.net