1

I started using PostSharp recently, mainly because I want to implement Method Cache. I found few examples of how to do it, but all these examples are based on implementing a cache method attribute and decorating methods which results should be cached:

I would like to implement the cache in a way to be able to set some additional perameters for each method in run time based on configuration. For example I would like to register a particular method cache with individual expiration time, but I do not know that value during code compilation.

The thing I do not how to do is how to do it during runtime, without decorating the methods.

Sebastian Widz
  • 1,962
  • 4
  • 26
  • 45
  • The only way PostSharp can add caching to your methods is by weaving IL code at build-time. If you need to control the caching behavior at run-time, then you can check the current configuration from within the aspect interception code. For example, you can proceed with the original method invocation immediately if the caching has not been enabled for this particular method. Of course, this doesn't help you to avoid decorating the methods. – AlexD Oct 22 '15 at 14:16

1 Answers1

1

This shall be simple, though you need to code the details you need, following are the important details, pasting my code, so some variables are our custom, modify them accordingly. You need to apply [ViewrCache] attribute to the relevant method post creating the underneath code and it will the modify the method IL accordingly at runtime

Create a custom caching attribute extended from PostSharp.Aspects.MethodInterceptionAspect as follows:

 [Serializable]
    public sealed class ViewrCacheAttribute : MethodInterceptionAspect

Class Variables:

// Cache Expiration from Config file

private static readonly int CacheTimeOut = Convert.ToInt32(WebConfigurationManager.AppSettings[CacheSettings.CacheTimeOutKey]);

// Parameters to be ignored from the Cache Key

private string[] IgnoreParameters { get; set; }

Override the method OnInvoke(MethodInterceptionArgs args) as follows:

// My custom implementation that you may want to change
public override void OnInvoke(MethodInterceptionArgs args)
        {
            // Fetch standard Cache
            var cache = MemoryCache.Default;

            // Fetch Cache Key using the Method arguments
            string cacheKey = GetCacheKey(args); // Code pasted below

            var cacheValue = cache.Get(cacheKey);

            if (cacheValue != null)
            {
                args.ReturnValue = cacheValue;

                return;
            }
            ReloadCache(cacheKey, args);
        }

// Get Cache Key method

 private string GetCacheKey(MethodInterceptionArgs args)
        {
            //need to exclude paging Parameters from Key

            var builder = new StringBuilder();

            var returnKey = new ViewrCacheKey { CallingMethodFullName = args.Method.ToString() };

            // Loop through the Call arguments / parameters
            foreach (var argument in args.Arguments)
            {
                if (argument != null)
                {
                    if ((IgnoreParameters == null) ||
                        (IgnoreParameters != null && !IgnoreParameters.Contains(argument.ToString())))
                        builder.Append(JsonConvert.SerializeObject(argument));
                }
            }

            returnKey.ControllerHash = builder.ToString();

            return JsonConvert.SerializeObject(returnKey);
        }

// Reload Cache

private Object ReloadCache(string cacheKey, MethodInterceptionArgs args)
        {
            //call the actual Method
            base.OnInvoke(args);

            //Save result into local cache
            InsertCache(cacheKey, args.ReturnValue);
            return args.ReturnValue;
        }

// Insert Cache

 private void InsertCache(string key, object value)
        {
            // Setting Cache Item Policy
            var policy = new CacheItemPolicy
            {
                SlidingExpiration = new TimeSpan(0, 0, CacheTimeOut)
            };

            // sliding Expiration Timeout in Seconds
            ObjectCache cache = MemoryCache.Default;

            // Set the key,value in the cache
            cache.Set(key, value, policy);
        }

// ViewR Cache Key

public class ViewrCacheKey
    {
        /// <summary>
        /// 
        /// </summary>
        public string CallingMethodFullName { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public string ControllerHash { get; set; }
    }
Mrinal Kamboj
  • 11,300
  • 5
  • 40
  • 74
  • Thank you for your example, but it does not answer my question. You created similar example as in the links I put in my post. My problem is defferent. I need to register methods into caching mechanism in runtime, not by decorating them with an attribute. – Sebastian Widz Oct 15 '15 at 16:08
  • You plan to add an Caching aspect at runtime for a given Method, but Post Sharp work by inserting the necessary IL for execution at run time for the decorated method, before actual method logic executes, if relevant data is not in Cache. Let me check not sure Post Sharp that work using declarative attributes can do attach to a method at run time – Mrinal Kamboj Oct 15 '15 at 18:01
  • couple of links that may help: http://doc.postsharp.net/iaspectprovider http://stackoverflow.com/questions/27693438/postsharp-how-to-know-at-runtime-if-a-certain-aspect-was-applied-to-a-method http://stackoverflow.com/questions/2461862/adding-code-to-the-beginning-end-of-methods-in-runtime-dynamically – Mrinal Kamboj Oct 15 '15 at 18:06