代码改变世界

定义 ICache 接口,以及实现默认的 ASP.NET 缓存机制

2013-06-28 15:28  音乐让我说  阅读(686)  评论(0编辑  收藏  举报

本文定义 ICache 接口,以及实现默认的 ASP.NET 缓存机制(即通过 System.Web.Caching.Cache)来缓存,将来也可以通过扩展,替换默认实现。

下面直接贴代码了:

ICache 接口

基础接口 - ICache

using System;
using System.Collections;
using System.Collections.Generic;

public interface ICache
{
    void Clear();
    bool Contains(string key);
    object Get(object key);
    T Get<T>(object key);
    IList<CacheItemDescriptor> GetDescriptors();
    T GetOrInsert<T>(object key, int timeToLiveInSeconds, bool slidingExpiration, Func<T> fetcher);
    void Insert(object key, object value);
    void Insert(object key, object value, int timeToLive, bool slidingExpiration);
    void Insert(object key, object value, int timeToLive, bool slidingExpiration, CacheItemPriority priority);
    void Remove(object key);
    void RemoveAll(ICollection keys);

    int Count { get; }

    ICollection Keys { get; }
}

结束标记。

CacheAspNet

依赖 Web 运行时的缓存

using System;
using System.Collections;
using System.Collections.Generic;
using System.Web;
using System.Web.Caching;

public class CacheAspNet : ICache
{
    private Cache _cache;
    private CacheSettings _settings;

    public CacheAspNet()
    {
        this._settings = new CacheSettings();
        this.Init(new CacheSettings());
    }

    public CacheAspNet(CacheSettings settings)
    {
        this._settings = new CacheSettings();
        this.Init(settings);
    }

    private string BuildKey(object key)
    {
        if (this._settings.UsePrefix) return (this._settings.PrefixForCacheKeys + "." + key.ToString());
        return key.ToString();
    }

    public void Clear()
    {
        ICollection keys = this.Keys;
        foreach (string str in keys)
        {
            string key = this.BuildKey(str);
            this._cache.Remove(key);
        }
    }

    public bool Contains(string key)
    {
        string str = this.BuildKey(key);
        if (this._cache.Get(str) == null) return false;
        return true;
    }

    private System.Web.Caching.CacheItemPriority ConvertToAspNetPriority(CacheItemPriority priority)
    {
        if (priority == CacheItemPriority.Normal) return System.Web.Caching.CacheItemPriority.Normal;
        if (priority == CacheItemPriority.High) return System.Web.Caching.CacheItemPriority.High;
        if (priority == CacheItemPriority.Low) return System.Web.Caching.CacheItemPriority.Low;
        if (priority == CacheItemPriority.Normal) return System.Web.Caching.CacheItemPriority.Normal;
        return System.Web.Caching.CacheItemPriority.NotRemovable;
    }

    public T Get<T>(object key)
    {
        string str = this.BuildKey(key);
        object obj2 = this._cache.Get(str);
        if (obj2 == null) return default(T);
        return (T) obj2;
    }

    public object Get(object key)
    {
        string str = this.BuildKey(key);
        return this._cache.Get(str);
    }

    public IList<CacheItemDescriptor> GetDescriptors()
    {
        IList<CacheItemDescriptor> list = new List<CacheItemDescriptor>();
        IEnumerator enumerator = this.Keys.GetEnumerator();
        while (enumerator.MoveNext())
        {
            string current = enumerator.Current as string;
            object obj2 = this.Get(current);
            list.Add(new CacheItemDescriptor(current, obj2.GetType().FullName));
        }
        ((List<CacheItemDescriptor>) list).Sort((Comparison<CacheItemDescriptor>) ((c1, c2) => c1.Key.CompareTo(c2.Key)));
        return list;
    }

    public T GetOrInsert<T>(object key, int timeToLiveInSeconds, bool slidingExpiration, Func<T> fetcher)
    {
        object obj2 = this.Get(key);
        if (obj2 == null)
        {
            T local = fetcher();
            this.Insert(key, local, timeToLiveInSeconds, slidingExpiration);
            return local;
        }
        return (T) obj2;
    }

    private void Init(CacheSettings settings)
    {
        this._cache = HttpRuntime.Cache;
        this._settings = settings;
    }

    public void Insert(object key, object value)
    {
        this.Insert(key, value, this._settings.DefaultTimeToLive, this._settings.DefaultSlidingExpirationEnabled, this._settings.DefaultCachePriority);
    }

    public void Insert(object key, object value, int timeToLive, bool slidingExpiration)
    {
        this.Insert(key, value, timeToLive, slidingExpiration, this._settings.DefaultCachePriority);
    }

    public void Insert(object keyName, object value, int timeToLive, bool slidingExpiration, CacheItemPriority priority)
    {
        TimeSpan span = TimeSpan.FromSeconds((double) timeToLive);
        if (keyName == null)
        {
            throw new ArgumentNullException("keyName");
        }
        if(TimeSpan.Zero > span)
        {
            throw new ArgumentException("timeToLive");
        }
        System.Web.Caching.CacheItemPriority priority2 = this.ConvertToAspNetPriority(priority);
        string key = this.BuildKey(keyName);
        if (TimeSpan.Zero < span)
        {
            if (slidingExpiration)
            {
                this._cache.Insert(key, value, null, Cache.NoAbsoluteExpiration, span, priority2, null);
            }
            else
            {
                DateTime absoluteExpiration = DateTime.Now.AddSeconds((double)timeToLive);
                this._cache.Insert(key, value, null, absoluteExpiration, Cache.NoSlidingExpiration, priority2, null);
            }
        }
        else
        {
            this._cache.Insert(key, value, null, Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration, priority2, null);
        }
    }

    public void Remove(object key)
    {
        string str = this.BuildKey(key);
        this._cache.Remove(str);
    }

    public void RemoveAll(ICollection keys)
    {
        foreach (object obj2 in keys)
        {
            string key = this.BuildKey((string) obj2);
            this._cache.Remove(key);
        }
    }

    public int Count
    {
        get
        {
            if (!this._settings.UsePrefix) return this._cache.Count;
            int num = 0;
            foreach (DictionaryEntry entry in this._cache)
            {
                string key = (string) entry.Key;
                if (key.StartsWith(this._settings.PrefixForCacheKeys))
                {
                    num++;
                }
            }
            return num;
        }
    }

    public ICollection Keys
    {
        get
        {
            IList<string> list = new List<string>();
            foreach (DictionaryEntry entry in this._cache)
            {
                string key = (string) entry.Key;
                if (!this._settings.UsePrefix)
                {
                    list.Add(key);
                }
                else if (key.StartsWith(this._settings.PrefixForCacheKeys))
                {
                    list.Add(key.Substring(this._settings.PrefixForCacheKeys.Length + 1));
                }
            }
            return (list as ICollection);
        }
    }

    public CacheSettings Settings
    {
        get
        {
            return this._settings;
        }
    }
}

CacheItemPriority.cs

using System;

public enum CacheItemPriority
{
    Default = 1,
    High = 2,
    Low = 0,
    Normal = 1,
    NotRemovable = 3
}

CacheItemDescriptor.cs

using System;

public class CacheItemDescriptor
{
    private string _key;
    private string _serializedData;
    private string _type;

    public CacheItemDescriptor(string key, string type) : this(key, type, string.Empty)
    {
    }

    public CacheItemDescriptor(string key, string type, string serializedData)
    {
        this._serializedData = string.Empty;
        this._key = key;
        this._type = type;
        this._serializedData = serializedData;
    }

    public string Data
    {
        get
        {
            return this._serializedData;
        }
    }

    public string ItemType
    {
        get
        {
            return this._type;
        }
    }

    public string Key
    {
        get
        {
            return this._key;
        }
    }
}

CacheSettings.cs

using System;

public class CacheSettings
{
    public CacheItemPriority DefaultCachePriority = CacheItemPriority.Normal;
    public bool DefaultSlidingExpirationEnabled = false;
    public int DefaultTimeToLive = 600;
    public string PrefixForCacheKeys = "cmnlib";
    public bool UsePrefix = true;
}

Cacher.cs

using System;
using System.Collections;
using System.Collections.Generic;

public class Cacher
{
    private static ICache _provider = new CacheAspNet();

    public static void Clear()
    {
        _provider.Clear();
    }

    public static bool Contains(string key)
    {
        return _provider.Contains(key);
    }

    public static object Get(object key)
    {
        return _provider.Get(key);
    }

    public static T Get<T>(object key)
    {
        return _provider.Get<T>(key);
    }

    public static T Get<T>(string key, int timeInSeconds, Func<T> fetcher)
    {
        return Get<T>(key, true, timeInSeconds, false, fetcher);
    }

    public static T Get<T>(string key, TimeSpan timeInSeconds, Func<T> fetcher)
    {
        return Get<T>(key, true, timeInSeconds.Seconds, false, fetcher);
    }

    public static T Get<T>(string key, bool useCache, TimeSpan timeInSeconds, Func<T> fetcher)
    {
        return Get<T>(key, useCache, timeInSeconds.Seconds, false, fetcher);
    }

    public static T Get<T>(string key, bool useCache, int timeInSeconds, bool slidingExpiration, Func<T> fetcher)
    {
        if (!useCache) return fetcher();
        return _provider.GetOrInsert<T>(key, timeInSeconds, slidingExpiration, fetcher);
    }

    public static IList<CacheItemDescriptor> GetDescriptors()
    {
        return _provider.GetDescriptors();
    }

    public static void Init(ICache cacheProvider)
    {
        _provider = cacheProvider;
    }

    public static void Insert(object key, object value)
    {
        _provider.Insert(key, value);
    }

    public static void Insert(object key, object value, int timeToLive, bool slidingExpiration)
    {
        _provider.Insert(key, value, timeToLive, slidingExpiration);
    }

    public static void Insert(object key, object value, int timeToLive, bool slidingExpiration, CacheItemPriority priority)
    {
        _provider.Insert(key, value, timeToLive, slidingExpiration, priority);
    }

    public static void Remove(object key)
    {
        _provider.Remove(key);
    }

    public static void RemoveAll(ICollection keys)
    {
        _provider.RemoveAll(keys);
    }

    public static int Count
    {
        get
        {
            return _provider.Count;
        }
    }

    public static ICollection Keys
    {
        get
        {
            return _provider.Keys;
        }
    }

    public static ICache Provider
    {
        get
        {
            return _provider;
        }
    }
}

 结束标记。

RuntimeMomoryCache

备注:.NET 4.0 增加了一个 System.Runtime.Caching.Momory 类,不依赖 Web。

代码如下:

public class RuntimeMemoryCache : ICache
{
    // Fields
    private readonly MemoryCache _cache = MemoryCache.Default;

    // Methods
    public void Add(string key, object value, TimeSpan timeSpan)
    {
        if (!string.IsNullOrEmpty(key) && value != null) this._cache.Add(key, value, DateTimeOffset.Now.Add(timeSpan), null);
    }

    public void AddWithFileDependency(string key, object value, string fullFileNameOfFileDependency)
    {
        if (!string.IsNullOrEmpty(key) && value != null)
        {
            CacheItemPolicy policy = new CacheItemPolicy {
                AbsoluteExpiration = DateTimeOffset.Now.AddMonths(1)
            };
            policy.ChangeMonitors.Add(new HostFileChangeMonitor(new List<string> { fullFileNameOfFileDependency }));
            this._cache.Add(key, value, policy, null);
        }
    }

    public void Clear()
    {
        foreach (string str in this._cache.AsParallel<KeyValuePair<string, object>>().ToDictionary<KeyValuePair<string, object>, string>(a => a.Key).Keys)
        {
            this._cache.Remove(str, null);
        }
    }

    public object Get(string cacheKey)
    {
        return this._cache[cacheKey];
    }

    public void MarkDeletion(string key, object value, TimeSpan timeSpan)
    {
        this.Remove(key);
    }

    public void Remove(string cacheKey)
    {
        this._cache.Remove(cacheKey, null);
    }

    public void Set(string key, object value, TimeSpan timeSpan)
    {
        this._cache.Set(key, value, DateTimeOffset.Now.Add(timeSpan), null);
    }
}

结束标记。

分布式缓存 - Memcached

利用 Memcached 实现分布式缓存。

MemcachedClient 使用的是 Enyim.Caching。开源地址:https://github.com/enyim/EnyimMemcached

public class MemcachedCache : ICache
{
    // Fields
    private MemcachedClient cache = new MemcachedClient();

    // Methods
    public void Add(string key, object value, TimeSpan timeSpan)
    {
        key = key.ToLower();
        this.cache.Store(3, key, value, DateTime.Now.Add(timeSpan));
    }

    public void AddWithFileDependency(string key, object value, string fullFileNameOfFileDependency)
    {
        this.Add(key, value, new TimeSpan(30, 0, 0, 0));
    }

    public void Clear()
    {
        this.cache.FlushAll();
    }

    public object Get(string cacheKey)
    {
        cacheKey = cacheKey.ToLower();
        HttpContext current = HttpContext.Current;
        if (current != null && current.Items.Contains(cacheKey)) return current.Items[cacheKey];
        object obj2 = this.cache.Get(cacheKey);
        if (current != null && obj2 != null) current.Items[cacheKey] = obj2;
        return obj2;
    }

    public Dictionary<string, Dictionary<string, string>> GetStatistics()
    {
        throw new NotImplementedException();
    }

    public void MarkDeletion(string key, object value, TimeSpan timeSpan)
    {
        this.Set(key, value, timeSpan);
    }

    public void Remove(string cacheKey)
    {
        cacheKey = cacheKey.ToLower();
        this.cache.Remove(cacheKey);
    }

    public void Set(string key, object value, TimeSpan timeSpan)
    {
        this.Add(key, value, timeSpan);
    }
}

 

谢谢浏览!