locked
MemoryCache with Attribute RRS feed

  • Question

  • I need to cache the results of method calls by time. I saw this MemoryCache class, but how can I create an Attribute like Asp.net MVC Cache?

    To do that, I think I need to intercept the calling method, but how can I do that?

    public class ProfileSelectionService : IProfileSelectionService
        {
            private readonly IWmbWebService webService;
            private readonly ISessionManager sessionManager;
    
            public ProfileSelectionService(IWmbWebService webService, ISessionManager sessionManager)
            {
                this.webService = webService;
                this.sessionManager = sessionManager;
            }
    
            public IEnumerable<StreamServer> GetServers()
            {
                return sessionManager.IsUserLogged() ? webService.GetServers() : Enumerable.Empty<StreamServer>();
            }
    
            public IEnumerable<Profile> GetProfiles()
            {
                return sessionManager.IsUserLogged() ? webService.GetProfiles() : Enumerable.Empty<Profile>();
            }
        }

    For example, the above class calls a WebService, but I don't need to call it everytime and I don't want write cache logic to this class either, because it will break the Single Responsability Principle among other things.

    If it helps, I'm using an IoC container to resolve dependencies. I'm using Unity


    Take a look at WPF FlashMessage
    About.me


    • Edited by Joba Diniz Wednesday, June 19, 2013 2:35 PM
    Wednesday, June 19, 2013 2:24 PM

Answers

  • Never mind. I did it. Actually it was very simple with Interceptors. Here's the code for future searches:

    public class CacheBehavior : IInterceptionBehavior
        {
            public IEnumerable<Type> GetRequiredInterfaces()
            {
                return Type.EmptyTypes;
            }
    
            public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
            {
                var attribute = input.MethodBase.GetCustomAttributes(typeof(CacheAttribute), false).FirstOrDefault() as CacheAttribute;
                if (attribute == null)
                    return getNext()(input, getNext);
    
                var key = string.Format("{0}.{1}", input.MethodBase.DeclaringType.ToString(), input.MethodBase.Name);
                var entry = MemoryCache.Default.Get(key);
                if (entry != null)
                    return input.CreateMethodReturn(entry);
    
                var result = getNext()(input, getNext);
                if (result.Exception == null)
                    MemoryCache.Default.Add(key, result.ReturnValue, DateTime.Now.AddMilliseconds(attribute.Duration));
                return result;
            }
    
            public bool WillExecute
            {
                get { return true; }
            }
        }

    [AttributeUsage(AttributeTargets.Method, Inherited = true, AllowMultiple = false)]
        public class CacheAttribute : Attribute
        {
            /// <summary>
            /// Duração em milessegundos.
            /// </summary>
            public double Duration { get; set; }
        }

    container.RegisterType<IProfileSelectionService, ProfileSelectionService>(
                    new ContainerControlledLifetimeManager(),
                    new Interceptor<VirtualMethodInterceptor>(),
                    new InterceptionBehavior<CacheBehavior>());
    [Cache(Duration = 60000)]
            public virtual IEnumerable<StreamServer> GetServers()
            {
                return sessionManager.IsUserLogged() ? webService.GetServers() : Enumerable.Empty<StreamServer>();
            }


    Take a look at WPF FlashMessage
    About.me


    • Edited by Joba Diniz Wednesday, June 19, 2013 5:48 PM more code
    • Marked as answer by Mike Feng Thursday, June 20, 2013 6:05 AM
    Wednesday, June 19, 2013 5:47 PM

All replies

  • Never mind. I did it. Actually it was very simple with Interceptors. Here's the code for future searches:

    public class CacheBehavior : IInterceptionBehavior
        {
            public IEnumerable<Type> GetRequiredInterfaces()
            {
                return Type.EmptyTypes;
            }
    
            public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
            {
                var attribute = input.MethodBase.GetCustomAttributes(typeof(CacheAttribute), false).FirstOrDefault() as CacheAttribute;
                if (attribute == null)
                    return getNext()(input, getNext);
    
                var key = string.Format("{0}.{1}", input.MethodBase.DeclaringType.ToString(), input.MethodBase.Name);
                var entry = MemoryCache.Default.Get(key);
                if (entry != null)
                    return input.CreateMethodReturn(entry);
    
                var result = getNext()(input, getNext);
                if (result.Exception == null)
                    MemoryCache.Default.Add(key, result.ReturnValue, DateTime.Now.AddMilliseconds(attribute.Duration));
                return result;
            }
    
            public bool WillExecute
            {
                get { return true; }
            }
        }

    [AttributeUsage(AttributeTargets.Method, Inherited = true, AllowMultiple = false)]
        public class CacheAttribute : Attribute
        {
            /// <summary>
            /// Duração em milessegundos.
            /// </summary>
            public double Duration { get; set; }
        }

    container.RegisterType<IProfileSelectionService, ProfileSelectionService>(
                    new ContainerControlledLifetimeManager(),
                    new Interceptor<VirtualMethodInterceptor>(),
                    new InterceptionBehavior<CacheBehavior>());
    [Cache(Duration = 60000)]
            public virtual IEnumerable<StreamServer> GetServers()
            {
                return sessionManager.IsUserLogged() ? webService.GetServers() : Enumerable.Empty<StreamServer>();
            }


    Take a look at WPF FlashMessage
    About.me


    • Edited by Joba Diniz Wednesday, June 19, 2013 5:48 PM more code
    • Marked as answer by Mike Feng Thursday, June 20, 2013 6:05 AM
    Wednesday, June 19, 2013 5:47 PM
  • Hi Joba,

    Thanks for sharing.

    Best regards,


    Mike Feng
    MSDN Community Support | Feedback to us
    Develop and promote your apps in Windows Store
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Thursday, June 20, 2013 6:06 AM