在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; }
}
}
}