Web开发中关于缓存的使用

        在Web Form开发中,发现有一个很好的东西叫ViewState,在封装好的控件中大量使用ViewSatate,特别是封装得越好,功能越强大的控件,ViewState使用越多,当然占用资源也越多。ViewState在最后解析成html的时候其实是通过加密处理放在一个隐藏域中,可以把这个隐藏域的值复制出来保存在记事本中,看看到底有多大,如果发现这个保存txt文件有几MB,那么这个ViewState使用就有问题了,页面肯定会很慢,因为页面的html太多了,浏览器可能会被卡死。隐藏域是一个input,在表单提交的时候会被提交到服务器的,如果ViewState太多,增加服务器的压力。

        可以想像,如果没有分页,页面直接显示出几千页的数据,浏览器会是什么效果。Web Form提供了方便快捷的开发,同时也增加了其复杂度,人为增加了Page页面的生命周期,平时注意使用ViewState,并不是所有的东西都需要ViewState,也并不是所有需要缓存的东西都放在ViewState,Session中。当然现在开始流行 ASP.NET MVC,并不意味着Web Form就落伍淘汰了,Web Form仍然具有他的优势,只要好好的利用同样能够实现很好的效果。


1、这里介绍微软提供的Web开发的一种缓存方式:

System.Web.Caching.Cache

这里的Cache通过键值对进行缓存,设定缓存时间,缓存级别等,下面可以看看这个类的源码

using System;
using System.Collections;
using System.Reflection;

namespace System.Web.Caching
{
    /// <summary>
    /// 实现用于 Web 应用程序的缓存。无法继承此类。
    /// </summary>
    public sealed class Cache : IEnumerable
    {
        // Fields
        private CacheInternal _cacheInternal;
        /// <summary>
        ///  用于 System.Web.Caching.Cache.Insert(System.String,System.Object) 方法调用中的 absoluteExpiration 
        ///  参数中以指示项从不到期。此字段为只读。
        /// </summary>
        public static readonly DateTime NoAbsoluteExpiration = DateTime.MaxValue;
        /// <summary>
        ///  用作 System.Web.Caching.Cache.Insert(System.String,System.Object) 或 System.Web.Caching.Cache.Add(System.String,System.Object,System.Web.Caching.CacheDependency,System.DateTime,System.TimeSpan,System.Web.Caching.CacheItemPriority,System.Web.Caching.CacheItemRemovedCallback) 
        ///  方法调用中的 slidingExpiration 参数,以禁用可调到期。此字段为只读。
        /// </summary>
        public static readonly TimeSpan NoSlidingExpiration = TimeSpan.Zero;
        private static CacheItemRemovedCallback s_sentinelRemovedCallback = new CacheItemRemovedCallback(SentinelEntry.OnCacheItemRemovedCallback);

        // Methods
        [SecurityPermission(SecurityAction.Demand, Unrestricted = true)]
        public Cache()
        {
        }

        internal Cache(int dummy)
        {
        }

        /// <summary>
        /// 将指定项添加到 System.Web.Caching.Cache 对象,该对象具有依赖项、到期和优先级策略以及一个委托(可用于在从 Cache 移除插入项时通知应用程序)
        /// </summary>
        /// <param name="key">用于引用该项的缓存键。</param>
        /// <param name="value">要添加到缓存的项。</param>
        /// <param name="dependencies">该项的文件依赖项或缓存键依赖项。当任何依赖项更改时,该对象即无效,并从缓存中移除。如果没有依赖项,则此参数包含 null。</param>
        /// <param name="absoluteExpiration">所添加对象将到期并被从缓存中移除的时间。如果使用可调到期,则 absoluteExpiration 参数必须为 System.Web.Caching.Cache.NoAbsoluteExpiration。</param>
        /// <param name="slidingExpiration">最后一次访问所添加对象时与该对象到期时之间的时间间隔。如果该值等效于 20 分钟,则对象在最后一次被访问 20 分钟之后将到期并从缓存中移除。如果使用绝对到期,
        /// 则 slidingExpiration 参数必须为 System.Web.Caching.Cache.NoSlidingExpiration。</param>
        /// <param name="priority">对象的相对成本,由 System.Web.Caching.CacheItemPriority 枚举表示。缓存在退出对象时使用该值;具有较低成本的对象在具有较高成本的对象之前被从缓存移除。</param>
        /// <param name="onRemoveCallback">在从缓存中移除对象时所调用的委托(如果提供)。当从缓存中删除应用程序的对象时,可使用它来通知应用程序。</param>
        /// <returns>如果该项先前存储在 Cache 中,则为 System.Object,否则为 null。</returns>        
        public object Add(string key, object value, CacheDependency dependencies, DateTime absoluteExpiration, TimeSpan slidingExpiration, CacheItemPriority priority, CacheItemRemovedCallback onRemoveCallback)
        {
            DateTime utcAbsoluteExpiration = DateTimeUtil.ConvertToUniversalTime(absoluteExpiration);
            return this._cacheInternal.DoInsert(true, key, value, dependencies, utcAbsoluteExpiration, slidingExpiration, priority, onRemoveCallback, false);
        }
        /// <summary>
        ///  从 System.Web.Caching.Cache 对象检索指定项。
        /// </summary>
        /// <param name="key"> 要检索的缓存项的标识符。</param>
        /// <returns>检索到的缓存项,未找到该键时为 null。</returns>
        public object Get(string key)
        {
            return this._cacheInternal.DoGet(true, key, CacheGetOptions.None);
        }

        internal object Get(string key, CacheGetOptions getOptions)
        {
            return this._cacheInternal.DoGet(true, key, getOptions);
        }

        public IDictionaryEnumerator GetEnumerator()
        {
            return this._cacheInternal.GetEnumerator();
        }

        public void Insert(string key, object value)
        {
            this._cacheInternal.DoInsert(true, key, value, null, NoAbsoluteExpiration, NoSlidingExpiration, CacheItemPriority.Normal, null, true);
        }

        public void Insert(string key, object value, CacheDependency dependencies)
        {
            this._cacheInternal.DoInsert(true, key, value, dependencies, NoAbsoluteExpiration, NoSlidingExpiration, CacheItemPriority.Normal, null, true);
        }

        public void Insert(string key, object value, CacheDependency dependencies, DateTime absoluteExpiration, TimeSpan slidingExpiration)
        {
            DateTime utcAbsoluteExpiration = DateTimeUtil.ConvertToUniversalTime(absoluteExpiration);
            this._cacheInternal.DoInsert(true, key, value, dependencies, utcAbsoluteExpiration, slidingExpiration, CacheItemPriority.Normal, null, true);
        }

        public void Insert(string key, object value, CacheDependency dependencies, DateTime absoluteExpiration, TimeSpan slidingExpiration, CacheItemUpdateCallback onUpdateCallback)
        {
            if (((dependencies == null) && (absoluteExpiration == NoAbsoluteExpiration)) && (slidingExpiration == NoSlidingExpiration))
            {
                throw new ArgumentException(SR.GetString("Invalid_Parameters_To_Insert"));
            }
            if (onUpdateCallback == null)
            {
                throw new ArgumentNullException("onUpdateCallback");
            }
            DateTime utcAbsoluteExpiration = DateTimeUtil.ConvertToUniversalTime(absoluteExpiration);
            this._cacheInternal.DoInsert(true, key, value, null, NoAbsoluteExpiration, NoSlidingExpiration, CacheItemPriority.NotRemovable, null, true);
            string[] cachekeys = new string[] { key };
            CacheDependency expensiveObjectDependency = new CacheDependency(null, cachekeys);
            if (dependencies == null)
            {
                dependencies = expensiveObjectDependency;
            }
            else
            {
                AggregateCacheDependency dependency2 = new AggregateCacheDependency();
                dependency2.Add(new CacheDependency[] { dependencies, expensiveObjectDependency });
                dependencies = dependency2;
            }
            this._cacheInternal.DoInsert(false, "w" + key, new SentinelEntry(key, expensiveObjectDependency, onUpdateCallback), dependencies, utcAbsoluteExpiration, slidingExpiration, CacheItemPriority.NotRemovable, s_sentinelRemovedCallback, true);
        }

        public void Insert(string key, object value, CacheDependency dependencies, DateTime absoluteExpiration, TimeSpan slidingExpiration, CacheItemPriority priority, CacheItemRemovedCallback onRemoveCallback)
        {
            DateTime utcAbsoluteExpiration = DateTimeUtil.ConvertToUniversalTime(absoluteExpiration);
            this._cacheInternal.DoInsert(true, key, value, dependencies, utcAbsoluteExpiration, slidingExpiration, priority, onRemoveCallback, true);
        }

        /// <summary>
        /// 从应用程序的 System.Web.Caching.Cache 对象移除指定项。
        /// </summary>
        /// <param name="key">要移除的缓存项的 System.String 标识符。</param>
        /// <returns>从 Cache 移除的项。如果未找到键参数中的值,则返回 null。</returns>
        public object Remove(string key)
        {
            CacheKey cacheKey = new CacheKey(key, true);
            return this._cacheInternal.DoRemove(cacheKey, CacheItemRemovedReason.Removed);
        }

        internal void SetCacheInternal(CacheInternal cacheInternal)
        {
            this._cacheInternal = cacheInternal;
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return ((IEnumerable)this._cacheInternal).GetEnumerator();
        }

        // Properties
        public int Count
        {
            get
            {
                return this._cacheInternal.PublicCount;
            }
        }

        public long EffectivePercentagePhysicalMemoryLimit
        {
            get
            {
                return this._cacheInternal.EffectivePercentagePhysicalMemoryLimit;
            }
        }

        public long EffectivePrivateBytesLimit
        {
            get
            {
                return this._cacheInternal.EffectivePrivateBytesLimit;
            }
        }

        public object this[string key]
        {
            get
            {
                return this.Get(key);
            }
            set
            {
                this.Insert(key, value);
            }
        }

        // Nested Types
        private class SentinelEntry
        {
            // Fields
            private CacheItemUpdateCallback _cacheItemUpdateCallback;
            private CacheDependency _expensiveObjectDependency;
            private string _key;

            // Methods
            public SentinelEntry(string key, CacheDependency expensiveObjectDependency, CacheItemUpdateCallback callback)
            {
                this._key = key;
                this._expensiveObjectDependency = expensiveObjectDependency;
                this._cacheItemUpdateCallback = callback;
            }

            public static void OnCacheItemRemovedCallback(string key, object value, CacheItemRemovedReason reason)
            {
                CacheItemUpdateReason expired;
                CacheItemUpdateCallback callback;
                Cache.SentinelEntry entry = value as Cache.SentinelEntry;
                switch (reason)
                {
                    case CacheItemRemovedReason.Expired:
                        expired = CacheItemUpdateReason.Expired;
                        goto Label_0034;

                    case CacheItemRemovedReason.Underused:
                        break;

                    case CacheItemRemovedReason.DependencyChanged:
                        expired = CacheItemUpdateReason.DependencyChanged;
                        if (!entry.ExpensiveObjectDependency.HasChanged)
                        {
                            goto Label_0034;
                        }
                        break;

                    default:
                        return;
                }
                return;
            Label_0034:
                callback = entry.CacheItemUpdateCallback;
                try
                {
                    CacheDependency dependency;
                    DateTime time;
                    TimeSpan span;
                    object obj2;
                    callback(entry.Key, expired, out obj2, out dependency, out time, out span);
                    if ((obj2 != null) && ((dependency == null) || !dependency.HasChanged))
                    {
                        HttpRuntime.Cache.Insert(entry.Key, obj2, dependency, time, span, entry.CacheItemUpdateCallback);
                    }
                    else
                    {
                        HttpRuntime.Cache.Remove(entry.Key);
                    }
                }
                catch (Exception exception)
                {
                    HttpRuntime.Cache.Remove(entry.Key);
                    try
                    {
                        WebBaseEvent.RaiseRuntimeError(exception, value);
                    }
                    catch
                    {
                    }
                }
            }

            // Properties
            public CacheItemUpdateCallback CacheItemUpdateCallback
            {
                get
                {
                    return this._cacheItemUpdateCallback;
                }
            }

            public CacheDependency ExpensiveObjectDependency
            {
                get
                {
                    return this._expensiveObjectDependency;
                }
            }

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

}

可以看出这个类的使用很简单,最主要的是 System.Web.UI.Page这个类默认使用了这个Cache类,

可以看看这个Page类的定义:

  public class Page : TemplateControl, IHttpHandler
    {       
        public Cache Cache { get; }
    }
这个Cache是一个public属性,可以直接使用,缓存保存在内存当中,用不着每次都从数据库或文件中读取,也可以不用使用这个ViewState

2、第二种就是使用微软企业库提供的一个缓存(这里不详细说明)


3、可以自己写一个缓存类

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

namespace ConsoleApplication1
{
    public sealed class Cache
    {
        private Dictionary<string, CacheObject> _directory = new Dictionary<string, CacheObject>();
        private static Cache _instance = null;
        private static string _lock = "lock";
        private Thread _thread = null;
        private int _interval = 5000;

        /// <summary>
        /// 自动清理时间间隔(默认5000毫秒)
        /// </summary>
        public int Interval
        {
            get { return _interval; }
            set { _interval = value; }
        }


        public static Cache GetInstance()
        {
            lock (_lock)
            {
                if (_instance == null)
                {
                    _instance = new Cache();
                }
                return _instance;
            }
        }

        private Cache()
            : this(true)
        {
            //
        }

        /// <summary>
        /// 自动清理过期缓存
        /// </summary>
        /// <param name="autoClear">true:自动清理;false:手动清理</param>
        private Cache(bool autoClear)
        {
            if (autoClear)
            {
                _thread = new Thread(new ThreadStart(ClearThread));
                //_thread.IsBackground = true;
                _thread.Start();
            }
        }

        private void ClearThread()
        {
            while (_directory != null)
            {
                Thread.Sleep(_interval);
                ClearTimeout();
            }
        }

        private void ClearTimeout()
        {
            lock (_directory)
            {
                List<string> list = new List<string>();
                foreach (KeyValuePair<string, CacheObject> item in _directory)
                {
                    if (item.Value.StopTime == null || item.Value.StopTime < DateTime.Now)
                    {
                        if (item.Value.CallBack != null)
                        {
                            item.Value.CallBack.Invoke(item.Value.StorageObject, null);
                        }

                        list.Add(item.Key);
                    }
                }

                foreach (string item in list)
                {
                    _directory.Remove(item);
                }
            }
        }

        /// <summary>
        /// 判断元素是否存在
        /// </summary>
        /// <param name="key">键</param>
        /// <returns>true|false</returns>
        public bool Exist(string key)
        {
            ClearTimeout();
            lock (_directory)
            {
                return _directory.ContainsKey(key);
            }
        }

        /// <summary>
        /// 移除元素
        /// </summary>
        /// <param name="key">键</param>
        /// <returns>true|false</returns>
        public bool Remove(string key)
        {
            lock (_directory)
            {
                CacheObject obj = null;
                if (_directory.TryGetValue(key, out obj))
                {
                    if (obj.CallBack != null)
                    {
                        obj.CallBack.Invoke(obj.StorageObject, null);
                    }
                }
                return _directory.Remove(key);
            }
        }

        /// <summary>
        /// 获取缓存数据
        /// </summary>
        /// <param name="key">键</param>
        /// <returns></returns>
        public object Get(string key)
        {
            ClearTimeout();
            object rtn = null;

            lock (_directory)
            {
                foreach (KeyValuePair<string, CacheObject> item in _directory)
                {
                    if (item.Key == key)
                    {
                        //针对按照时间间隔回收的,重新设置截至时间
                        if (item.Value.TimeSpan != TimeSpan.MinValue)
                        {
                            item.Value.StartTime = DateTime.Now;
                            item.Value.StopTime = DateTime.Now + item.Value.TimeSpan;
                        }
                        rtn = item.Value.StorageObject;
                        break;
                    }
                }
            }

            return rtn;
        }

        public object this[string key]
        {
            get
            {
                return Get(key);
            }
            set
            {
                ClearTimeout();
                Add(key, value);
            }
        }

        /// <summary>
        /// 添加缓存(默认缓存20分钟)
        /// 如果存在键,则替换对应的值
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="value">值</param>
        /// <returns>true|false</returns>
        public bool Add(string key, object value)
        {
            return Add(key, value, DateTime.Now.AddMinutes(20));
        }

        /// <summary>
        /// 添加缓存、指定过期时间
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="value">值</param>
        /// <param name="time">过期时间</param>        
        /// <returns></returns>
        public bool Add(string key, object value, DateTime time)
        {
            return Add(key, value, time, null);
        }

        /// <summary>
        /// 添加缓存、指定过期时间
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="value">值</param>
        /// <param name="time">过期时间</param>
        /// <param name="callBack">回调函数</param>
        /// <returns></returns>
        public bool Add(string key, object value, DateTime time, EventHandler callBack)
        {
            return Add(key, value, TimeSpan.MinValue, time, callBack);
        }

        /// <summary>
        ///  添加缓存(过期时间,与过期间隔只能二选一,优先使用过期间隔)
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="value">值</param>
        /// <param name="timeSpan">国企时间间隔</param>
        /// <param name="time">过期时间</param>   
        /// <param name="callBack">回调函数</param>
        /// <returns>true|false</returns>
        private bool Add(string key, object value, TimeSpan timeSpan, DateTime time, EventHandler callBack)
        {
            bool flag = false;
            lock (_directory)
            {
                //存在该键、则替换对应的值
                if (_directory.ContainsKey(key))
                {
                    foreach (KeyValuePair<string, CacheObject> item in _directory)
                    {
                        if (item.Key == key)
                        {
                            item.Value.StorageObject = value;
                            item.Value.CallBack = callBack;
                            flag = true;
                            break;
                        }
                    }
                }
                else
                {
                    CacheObject obj = new CacheObject();
                    obj.StorageObject = value;
                    obj.CallBack = callBack;
                    obj.TimeSpan = timeSpan;
                    obj.StartTime = DateTime.Now;

                    if (timeSpan == TimeSpan.MinValue)
                    {
                        obj.StopTime = time;
                    }
                    else
                    {
                        obj.StopTime = DateTime.Now + timeSpan;
                    }
                    _directory.Add(key, obj);

                    flag = true;
                }
            }

            return flag;
        }

        /// <summary>
        /// 添加缓存、指定过期时间间隔(只要在这个时间间隔之内连续访问就不会被回收)
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="value">值</param>
        /// <param name="timeSpan">最后一次访问时间与回收时间间隔、超过这个间隔会被回收</param>
        /// <returns></returns>
        public bool Add(string key, object value, TimeSpan timeSpan)
        {
            return Add(key, value, timeSpan, DateTime.MinValue, null);
        }

        /// <summary>
        /// 添加缓存、指定过期时间间隔(只要在这个时间间隔之内连续访问就不会被回收)
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="value">值</param>
        /// <param name="timeSpan">最后一次访问时间与回收时间间隔、超过这个间隔会被回收</param>
        /// <param name="callBack">回调函数</param>
        /// <returns></returns>
        public bool Add(string key, object value, TimeSpan timeSpan, EventHandler callBack)
        {
            return Add(key, value, timeSpan, DateTime.MinValue, callBack);
        }

    }

    class CacheObject
    {
        private object _storageObject = null;

        /// <summary>
        /// 缓存对象
        /// </summary>
        public object StorageObject
        {
            get { return _storageObject; }
            set { _storageObject = value; }
        }

        private DateTime _startTime = DateTime.Now;

        /// <summary>
        /// 开始缓存时间
        /// </summary>
        public DateTime StartTime
        {
            get { return _startTime; }
            set { _startTime = value; }
        }

        private DateTime _StopTime = DateTime.Now;

        /// <summary>
        /// 结束缓存时间
        /// </summary>
        public DateTime StopTime
        {
            get { return _StopTime; }
            set { _StopTime = value; }
        }

        private TimeSpan _timeSpan = TimeSpan.MinValue;

        /// <summary>
        /// 设置缓存回收时间间隔
        /// </summary>
        public TimeSpan TimeSpan
        {
            get { return _timeSpan; }
            set { _timeSpan = value; }
        }

        private EventHandler _callBack = null;

        /// <summary>
        /// 缓存移除时的回调函数
        /// </summary>
        public EventHandler CallBack
        {
            get { return _callBack; }
            set { _callBack = value; }
        }
    }

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值