AOP through Unity interceptors - Compression

, , , 0 Comments

Today we are going to compress our data. We will still use AOP through Unity.

The scenario is the following: we have a class generating a huge set of data (in our example, data structure is string). we don't want it to be kept in memory, because we will use it later, or not often. So one solution could be to compress this data & uncompress it once we will really need it.
public interface IBigDataRepo
    {
        string GetData();
    }
 public class BigDataRepo : IBigDataRepo
    {
        public string GetData()
        {
            return new string('X', 100000);
        }
    }
We are going to use is this way:

static void Main(string[] args)
        {
            using (var container = new UnityContainer())
            {
                container.AddNewExtension<Interception>();

                // Register
                container.RegisterType<IBigDataRepo, BigDataRepo>(
                    new Interceptor<InterfaceInterceptor>(),
                    new InterceptionBehavior<CompressionInterceptionBehavior>());

                // Resolve
                IBigDataRepo bigDataRepo = container.Resolve<IBigDataRepo>();

                // Call
                string compressedData = bigDataRepo.GetData();

                Console.WriteLine(compressedData.Length);

                Console.WriteLine("END");
                Console.ReadLine();

            }

        }
That's  all. Now, let's see how the CompressionInterceptionBehavior is made.

public class CompressionInterceptionBehavior : IInterceptionBehavior
    {
        public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
        {
            var result = getNext()(input, getNext);

            return input.CreateMethodReturn(Compress(result.ReturnValue));
        }

        private object Compress(object stringToCompress)
        {
            byte[] text = Encoding.ASCII.GetBytes(stringToCompress.ToString());
            using (MemoryStream memory = new MemoryStream())
            {
                using (GZipStream gzip = new GZipStream(memory, CompressionMode.Compress, true))
                {
                    gzip.Write(text, 0, text.Length);
                }
                 return Encoding.ASCII.GetString(memory.ToArray());
            }
        }

        public IEnumerable<Type> GetRequiredInterfaces()
        {
            return Type.EmptyTypes;
        }

        public bool WillExecute { get { return true; } }
    }

Simple enough. The most complicated part is the compression part :).

0 commentaires:

AOP through Unity interceptors - Performance monitoring

, , , , 0 Comments

Today we continue the serie on AOP with Performance monitoring.

The principle is very simple: we want to monitor the time a method took to execute.

Here is the code of the class.
public class PerformanceMonitoringInterceptionBehavior : IInterceptionBehavior
    {
        public IEnumerable<Type> GetRequiredInterfaces()
        {
            return Type.EmptyTypes;
        }

        public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
        {
            Stopwatch sw = Stopwatch.StartNew();
            var result = getNext()(input, getNext);
            sw.Stop();
             WriteLog(String.Format("Method {0} took {1} ms", input.MethodBase, sw.ElapsedMilliseconds));

            return result;
        }

        public bool WillExecute
        {
            get { return true; }
        }

        private void WriteLog(string message, string args = null)
        {
            var utcNow = DateTime.UtcNow;
            Console.WriteLine(
                "[{0}]-[{1}]: {2} {3}",
                utcNow.ToShortDateString(),
                utcNow.ToLongTimeString(),
                message,
                args);
        }
    }

As you can see, we only start & stop a Stopwatch to watch the time consumed by the method.

As always, you need to specify that you want to use the behavior:
container.RegisterType<IStore, StoreImpl>(
                    new Interceptor<InterfaceInterceptor>(),
                    new InterceptionBehavior<PerformanceMonitoringInterceptionBehavior>());
                 container.RegisterType<IFoo, FooImpl>(
                    new Interceptor<InterfaceInterceptor>(),
                    new InterceptionBehavior<PerformanceMonitoringInterceptionBehavior>());

0 commentaires:

AOP through Unity interceptors - Caching

, , , 0 Comments

Let's continue our serie on AOP with another popular usage of interception: caching.

Let's use the previously created project and add this class:
public class CachingInterceptionBehavior : IInterceptionBehavior
    {
        private static IDictionary<string, MemoryCache> Cache = new Dictionary<string, MemoryCache>();
        private static IList<string> SyncLock = new List<string>();
        private static object SyncRoot = new object();

        public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
        {
            if (input.MethodBase.GetCustomAttribute<IgnoreCacheAttribute>() != null)
            {
                return getNext()(input, getNext);
            }
            var arguments = JsonConvert.SerializeObject(input.Arguments);
            string key = string.Concat(input.MethodBase.DeclaringType.FullName, "|", input.MethodBase.ToString(), "|", arguments);
if (IsInCache(input.MethodBase.DeclaringType, key))
            {
                return input.CreateMethodReturn(GetFromCache(input.MethodBase.DeclaringType, key));
            }
            lock (SyncRoot)
            {
                if (!SyncLock.Contains(key))
                {
                    SyncLock.Add(key);
                }
            }
           
            lock (SyncLock[SyncLock.IndexOf(key)])
            {
                if (IsInCache(input.MethodBase.DeclaringType, key))
                {
                    return input.CreateMethodReturn(GetFromCache(input.MethodBase.DeclaringType, key));
                }

IMethodReturn result = getNext()(input, getNext);
                if (result.ReturnValue != null)
                {
                    AddToCache(input.MethodBase.DeclaringType, key, result.ReturnValue);
                }
return result;
            }
        }
        private void AddToCache(Type declaringType, string key, object toBeAddedToCache)
        {
            if (!Cache.ContainsKey(declaringType.FullName))
            {
                Cache.Add(declaringType.FullName, new MemoryCache(declaringType.FullName));
            }

            CacheItem item = new CacheItem(key, toBeAddedToCache);
Cache[declaringType.FullName].Add(item, new CacheItemPolicy { AbsoluteExpiration = new DateTimeOffset(DateTime.Now.AddDays(1)) });
        }
private object GetFromCache(Type declaringType, string key)
        {
            return Cache[declaringType.FullName].Get(key);
        }
private bool IsInCache(Type declaringType, string key)

        {
            return Cache.ContainsKey(declaringType.FullName) && Cache[declaringType.FullName].Contains(key);
        }
        public IEnumerable<Type> GetRequiredInterfaces()
        {
            return Type.EmptyTypes;
        }
        public bool WillExecute
        {
            get { return true; }
        }
    }

As you can see, we use the IgnoreCacheAttribute in order to avoid apply cache on choosen methods.

Here is its implementation:
    public class IgnoreCacheAttribute : Attribute
    {
    }

We have a global cache for every Declaring type of our application. When a method is called with the same parameters, we get info from cache instead of calling the real underlying object.

Here is a graphical explanation of how is structured our cache:



Don't forget to register:
// Register

                container.RegisterType<IStore, StoreImpl>(

                    new Interceptor<InterfaceInterceptor>(),

                   new InterceptionBehavior<CachingInterceptionBehavior>());



                container.RegisterType<IFoo, FooImpl>(

                    new Interceptor<InterfaceInterceptor>(),

                    new InterceptionBehavior<CachingInterceptionBehavior>());

0 commentaires: