Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Caching attribute for method?

Tags:

Maybe this is dreaming, but is it possible to create an attribute that caches the output of a function (say, in HttpRuntime.Cache) and returns the value from the cache instead of actually executing the function when the parameters to the function are the same?

When I say function, I'm talking about any function, whether it fetches data from a DB, whether it adds two integers, or whether it spits out the content of a file. Any function.

like image 391
PostgresQLNewb Avatar asked Mar 16 '11 16:03

PostgresQLNewb


People also ask

What is cache method?

How does Caching work? The data in a cache is generally stored in fast access hardware such as RAM (Random-access memory) and may also be used in correlation with a software component. A cache's primary purpose is to increase data retrieval performance by reducing the need to access the underlying slower storage layer.

What is cached response?

Response caching reduces the number of requests a client or proxy makes to a web server. Response caching also reduces the amount of work the web server performs to generate a response. Response caching is controlled by headers that specify how you want client, proxy, and middleware to cache responses.

What is cache in MVC?

Caching is used to improve the performance in ASP.NET MVC. Caching is a technique which stores something in memory that is being used frequently to provide better performance. In ASP.NET MVC, OutputCache attribute is used for applying Caching.


2 Answers

Your best bet is Postsharp. I have no idea if they have what you need, but that's certainly worth checking. By the way, make sure to publish the answer here if you find one.

EDIT: also, googling "postsharp caching" gives some links, like this one: Caching with C#, AOP and PostSharp

UPDATE: I recently stumbled upon this article: Introducing Attribute Based Caching. It describes a postsharp-based library on http://cache.codeplex.com/ if you are still looking for a solution.

like image 125
Dyppl Avatar answered Sep 29 '22 22:09

Dyppl


I have just the same problem - I have multiply expensive methods in my app and it is necessary for me to cache those results. Some time ago I just copy-pasted similar code but then I decided to factor this logic out of my domain. This is how I did it before:

    static List<News> _topNews = null;
    static DateTime _topNewsLastUpdateTime = DateTime.MinValue;
    const int CacheTime = 5;  // In minutes

    public IList<News> GetTopNews()
    {
        if (_topNewsLastUpdateTime.AddMinutes(CacheTime) < DateTime.Now)
        {
            _topNews = GetList(TopNewsCount);
        }

        return _topNews;
    }

And that is how I can write it now:

    public IList<News> GetTopNews()
    {
        return Cacher.GetFromCache(() => GetList(TopNewsCount));
    }

Cacher - is a simple helper class, here it is:

public static class Cacher
{
    const int CacheTime = 5;  // In minutes

    static Dictionary<long, CacheItem> _cachedResults = new Dictionary<long, CacheItem>();

    public static T GetFromCache<T>(Func<T> action)
    {
        long code = action.GetHashCode();

        if (!_cachedResults.ContainsKey(code))
        {
            lock (_cachedResults)
            {
                if (!_cachedResults.ContainsKey(code))
                {
                    _cachedResults.Add(code, new CacheItem { LastUpdateTime = DateTime.MinValue });
                }
            }
        }

        CacheItem item = _cachedResults[code];
        if (item.LastUpdateTime.AddMinutes(CacheTime) >= DateTime.Now)
        {
            return (T)item.Result;
        }

        T result = action();

        _cachedResults[code] = new CacheItem
        {
            LastUpdateTime = DateTime.Now,
            Result = result
        };

        return result;
    }
}


class CacheItem
{
    public DateTime LastUpdateTime { get; set; }
    public object Result { get; set; }
}

A few words about Cacher. You might notice that I don't use Monitor.Enter() ( lock(...) ) while computing results. It's because copying CacheItem pointer ( return (T)_cachedResults[code].Result; line) is thread safe operation - it is performed by only one stroke. Also it is ok if more than one thread will change this pointer at the same time - they all will be valid.

like image 44
Vladimir Avatar answered Sep 29 '22 21:09

Vladimir