Web開発におけるキャッシュの使用について

23805 ワード

Web Formの開発では、ViewStateという良いものが発見されました.パッケージされたコントロールの中でViewSatateを大量に使用しています.特にパッケージが良いほど、機能が強いコントロールほど、ViewStateが多く使用され、もちろんリソースも多く消費されています.ViewStateは最後にhtmlに解析する時実は暗号化処理を通じて1つの隠しドメインの中に置いて、この隠しドメインの値をコピーして手帳の中で保存することができて、いったいどれだけ大きいかを見て、もしこの保存txtファイルが何MBあることを発見したら、このViewStateの使用は問題があって、ページはきっと遅くて、ページのhtmlが多すぎるため、ブラウザが詰まって死ぬ可能性があります.非表示ドメインはinputであり、フォームのコミット時にサーバにコミットされます.ViewStateが多すぎると、サーバの圧力が増加します.
        ページングがなければ、ページに数千ページのデータが直接表示され、ブラウザがどのような効果をもたらすか想像できます.Web Formは便利で迅速な開発を提供し、複雑さも増し、Pageページのライフサイクルを人為的に増やし、普段はView Stateの使用に注意しているが、すべてのものがView Stateを必要としているわけではないし、キャッシュが必要なものがすべてView State、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、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; }
        }
    }

}