In every application you have some data that is more read-more,write-once or twice. For example you can have the list of Cities of a country,the list of Countries of the world or list of exchange currency. This data is modified rarely. Also,you can have data that is not very sensitive to be real-time,such as the list of invoices for the day.
In .NET 3.5 you have several options
1. ASP.NET caching  – and implementing in other applications with HttpRuntime  ( even if MS says “The Cache class is not intended for use outside of ASP.NET applications”)
2. Enterprise caching block : hard to configure
3. memcached,velocity,sharedcache and other third party providers – that comes with their options and configuration
In .NET 4.0 you have a new kid : objectcache and,more important,an implementation : MemoryCache
http://msdn.microsoft.com/en-us/library/system.runtime.caching.memorycache%28v=VS.100%29.aspx
What is very good is that now you can cache in Memory what do you want – and apply easily to your Business Layer. More,the object is a singleton for the application – that is even better (see the test on the final of the post)
What it is missing is an easy implementation for List and an implementation to remove data after a defined time.
So I decided to do my implementation for that (ok,it is wrong to have both implementations in a single class – but you can separate easily )
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Caching;
namespace CachingData{
    /// <summary>
    /// List<int> i = new List<int>() { 1,10,100 };
            //CacheData_List<List<int>,int> data = new CacheData_List<List<int>,int>(2);
            //data.Add(i);
            //Assert.AreEqual(3,data.Items().Count,"must be 3");
            //data = new CacheData_List<List<int>,int>();
            //Assert.AreEqual(3,data.Items().Count,"must be 3");
            //Assert.IsTrue(data.ContainsData,"must have data");
            //Thread.Sleep(1000 * 3);
            //Assert.IsFalse(data.ContainsData,"must not have data");
    /// </summary>
    /// <typeparam name="T">and generic ILIST </typeparam>
    /// <typeparam name="U"></typeparam>
    public class CacheData_List<T,U>
        where T:class,IList<U>,new()
    {
        /// <summary>
        /// use this for adding in cache
        /// </summary>
        public event EventHandler RemovedCacheItem;
        private System.Timers.Timer timerEvent;
        private MemoryCache buffer;
        private int TimeToLiveSeconds;
        private DateTimeOffset dto;
        private string Key;
        /// <summary>
        /// default constructor - cache 600 seconds = 10 minutes
        /// </summary>
        public CacheData_List()
            : this(600)
        {
        }
        /// <summary>
        /// constructor cache the mentioned TimeSeconds time
        /// </summary>
        /// <param name="TimeSeconds">value of time for cache</param>
        public CacheData_List(int TimeSeconds)
        {
            TimeToLiveSeconds = TimeSeconds;
            timerEvent=new System.Timers.Timer(TimeToLiveSeconds * 1000);
            timerEvent.AutoReset = true;
            timerEvent.Elapsed += new System.Timers.ElapsedEventHandler(timerEvent_Elapsed);
            dto = new DateTimeOffset(DateTime.UtcNow.AddSeconds(TimeToLiveSeconds));
            Key = typeof(T).ToString();
            buffer = MemoryCache.Default;
        }
        void timerEvent_Elapsed(object sender,System.Timers.ElapsedEventArgs e)
        {
            if (RemovedCacheItem != null)
            {
                RemovedCacheItem(this,EventArgs.Empty);
            }
        }
        /// <summary>
        /// remove item from cache
        /// </summary>
        public void Remove()
        {
            if (buffer.Contains(Key))
            {
                buffer.Remove(Key);
            }
            dto=new DateTimeOffset(DateTime.UtcNow.AddSeconds(TimeToLiveSeconds));
        }
        /// <summary>
        /// add multiple items to cache
        /// </summary>
        /// <param name="items">items to add to the cache</param>
        public void Add(T items)
        {
            if (buffer.Contains(Key))
            {
                T data = Items();
                foreach (var t in data)
                {
                    items.Add(t);
                }
                buffer.Remove(Key);
            }
            buffer.Add(Key,items,dto);
        }
        /// <summary>
        /// add a item to the IList of the cache
        /// </summary>
        /// <param name="item">an item to add</param>
        public void AddItem(U item)
        {
            T data=new T();
            if (buffer.Contains(Key))
            {
                data = buffer.Get(Key) as T;
                buffer.Remove(Key);
            }
            data.Add(item);
            buffer.Add(Key,data,dto);
        }
        /// <summary>
        /// usefull if you do not intercept the removed event
        /// </summary>
        public bool ContainsData
        {
            get
            {
                return buffer.Contains(Key);
            }
        }
        /// <summary>
        /// retrieve items
        /// </summary>
        /// <returns></returns>
        public T Items()
        {
            if (!buffer.Contains(Key))
                return null;
            return buffer.Get(Key) as T;
        }
    }
}
Please note that the test for usage is in the summary :
</pre>
List i = new List() { 1,10,100 };
CacheData_List <List<int>,int> data = new CacheData_List<List<int>,int>(2);
data.Add(i);
Assert.AreEqual(3,data.Items().Count,"must be 3");
data = new CacheData_List<List<int>,int>();
Assert.AreEqual(3,data.Items().Count,"must be 3");
Assert.IsTrue(data.ContainsData,"must have data");
Thread.Sleep(1000 * 3);
Assert.IsFalse(data.ContainsData,"must not have data");
You can download the file from
http://msprogrammer.serviciipeweb.ro/wp-content/uploads/2010/05/CachingData.zip
(Last Note : for synchonization maybe it was better to lock on readerwriterlockslim
Leave a Reply to Jeff Cancel reply