昨天有朋友说,使用PageAdapter要比BasePage好,使用PageAdapter便于统一管理和配置,这次我用PageAdapter实现同样的效果,同时也对原来的代码也做了一些修改,使之性能有所提升。
读取控件状态,不是直接从数据库读取,而是先去状态池中查找,如果状态池中不存在,我们再访问数据库。
保存的过程和读取的过程相对应,控件状态先保存至状态池,当状态池满时,将其中的部分元素保存只数据库。
状态池中的元素都是未序列化的,这样就避免了序列化和反序列化带来的性能问题。
Code
using System;
using System.Web.UI;
using System.IO;
using ICSharpCode.SharpZipLib.Zip.Compression;
using System.Collections;
using JianCaiWeb.DbAccess;
using System.Text;
using System.Collections.Generic;
namespace JianCaiWeb.Utils
{
/**//// <summary>
/// 读取控件状态,不是直接从数据库读取,而是先去状态池中查找,如果状态池中不存在,我们再访问数据库。
///
/// 状态池中的元素都是未序列化的,这样就避免了序列化和反序列化带来的性能问题。
/// </summary>
public class DatabasePageStatePersister : PageStatePersister
{
private static DataAccess da;
//状态池
private static List<DictionaryEntry> list = new List<DictionaryEntry>();
public DatabasePageStatePersister(Page page)
: base(page)
{
da = DataAccessFactory.CreateDataAccess();
}
//在 Page 对象初始化其控件层次结构时,加载保留的状态信息
public override void Load()
{
string stateID = base.Page.Request["__VIEWSTATE_KEY"].ToString();
Pair statePair = this.LoadViewState(stateID);
this.ViewState = statePair.First;
this.ControlState = statePair.Second;
}
// 在从内存中卸载 Page 对象时,对所保留的状态信息进行序列化。
public override void Save()
{
if (this.ViewState != null || this.ControlState != null)
{
Guid guid = Guid.NewGuid();
string viewStateID = guid.ToString();
base.Page.ClientScript.RegisterHiddenField("__VIEWSTATE_KEY", viewStateID);
Pair statePair = new Pair(ViewState, ControlState);
this.SaveViewState(viewStateID, statePair);
}
}
//保存视图状态至状态池或数据库
private void SaveViewState(string viewStateID, Pair statePair)
{
DictionaryEntry newEntry = new DictionaryEntry();
newEntry.Key = viewStateID;
newEntry.Value = statePair;
list.Add(newEntry);
//当al中的元素数量大于等于1000时,将其前10条放入数据库
if (list.Count >= 1000)
{
//声明一数组,用于存放al的前10条元素
DictionaryEntry[] entryArray = new DictionaryEntry[10];
//al的前10条元素拷贝至objs数组中
list.CopyTo(0, entryArray, 0, 10);
//从al中移除前10条元素
list.RemoveRange(0, 10);
//循环遍历objs,将其所包含的元素存入数据库中
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 10; i++)
{
DictionaryEntry oldEntry = entryArray[i];
//获取页面的StateFormmatter
IStateFormatter formatter = this.StateFormatter;
//序列化控件状态
string serializedState = formatter.Serialize(oldEntry.Value);
sb.Append(string.Format("insert into ViewState (viewStateID,ViewState) values ('{0}','{1}');", oldEntry.Key, serializedState));
}
//将控件状态存入数据库
da.ExecuteNonQuery(sb.ToString());
}
}
//从状态池或数据库中读取控件状态
private Pair LoadViewState(string viewStateID)
{
Pair statePair = null;
//遍历状态池,找到相应的控件状态
foreach (DictionaryEntry entry in list)
{
if (entry.Key.ToString() == viewStateID)
{
statePair = (Pair)entry.Value;
//list.Remove(entry);
break;
}
}
//如果状态池中没有找到相应的控件状态,则从数据库中读取
if (statePair == null)
{
string strSql = "select viewState from viewState where viewStateID = '" + viewStateID + "'";
string viewState = da.ExecuteScalar(strSql).ToString();
//获取页面的StateFormmatter
IStateFormatter formatter = this.StateFormatter;
//序列化控件状态
statePair = (Pair)formatter.Deserialize(viewState);
}
return statePair;
}
}
}
using System;
using System.Web.UI;
using System.IO;
using ICSharpCode.SharpZipLib.Zip.Compression;
using System.Collections;
using JianCaiWeb.DbAccess;
using System.Text;
using System.Collections.Generic;
namespace JianCaiWeb.Utils
{
/**//// <summary>
/// 读取控件状态,不是直接从数据库读取,而是先去状态池中查找,如果状态池中不存在,我们再访问数据库。
///
/// 状态池中的元素都是未序列化的,这样就避免了序列化和反序列化带来的性能问题。
/// </summary>
public class DatabasePageStatePersister : PageStatePersister
{
private static DataAccess da;
//状态池
private static List<DictionaryEntry> list = new List<DictionaryEntry>();
public DatabasePageStatePersister(Page page)
: base(page)
{
da = DataAccessFactory.CreateDataAccess();
}
//在 Page 对象初始化其控件层次结构时,加载保留的状态信息
public override void Load()
{
string stateID = base.Page.Request["__VIEWSTATE_KEY"].ToString();
Pair statePair = this.LoadViewState(stateID);
this.ViewState = statePair.First;
this.ControlState = statePair.Second;
}
// 在从内存中卸载 Page 对象时,对所保留的状态信息进行序列化。
public override void Save()
{
if (this.ViewState != null || this.ControlState != null)
{
Guid guid = Guid.NewGuid();
string viewStateID = guid.ToString();
base.Page.ClientScript.RegisterHiddenField("__VIEWSTATE_KEY", viewStateID);
Pair statePair = new Pair(ViewState, ControlState);
this.SaveViewState(viewStateID, statePair);
}
}
//保存视图状态至状态池或数据库
private void SaveViewState(string viewStateID, Pair statePair)
{
DictionaryEntry newEntry = new DictionaryEntry();
newEntry.Key = viewStateID;
newEntry.Value = statePair;
list.Add(newEntry);
//当al中的元素数量大于等于1000时,将其前10条放入数据库
if (list.Count >= 1000)
{
//声明一数组,用于存放al的前10条元素
DictionaryEntry[] entryArray = new DictionaryEntry[10];
//al的前10条元素拷贝至objs数组中
list.CopyTo(0, entryArray, 0, 10);
//从al中移除前10条元素
list.RemoveRange(0, 10);
//循环遍历objs,将其所包含的元素存入数据库中
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 10; i++)
{
DictionaryEntry oldEntry = entryArray[i];
//获取页面的StateFormmatter
IStateFormatter formatter = this.StateFormatter;
//序列化控件状态
string serializedState = formatter.Serialize(oldEntry.Value);
sb.Append(string.Format("insert into ViewState (viewStateID,ViewState) values ('{0}','{1}');", oldEntry.Key, serializedState));
}
//将控件状态存入数据库
da.ExecuteNonQuery(sb.ToString());
}
}
//从状态池或数据库中读取控件状态
private Pair LoadViewState(string viewStateID)
{
Pair statePair = null;
//遍历状态池,找到相应的控件状态
foreach (DictionaryEntry entry in list)
{
if (entry.Key.ToString() == viewStateID)
{
statePair = (Pair)entry.Value;
//list.Remove(entry);
break;
}
}
//如果状态池中没有找到相应的控件状态,则从数据库中读取
if (statePair == null)
{
string strSql = "select viewState from viewState where viewStateID = '" + viewStateID + "'";
string viewState = da.ExecuteScalar(strSql).ToString();
//获取页面的StateFormmatter
IStateFormatter formatter = this.StateFormatter;
//序列化控件状态
statePair = (Pair)formatter.Deserialize(viewState);
}
return statePair;
}
}
}
下边是继承PageAdapter的类,当页面的EnableViewState为true时,调用我们自定义的类(DataBasePageStatePersister),否则调用基类的实现。
Code
using System;
using System.Collections.Generic;
using System.Text;
using System.Web.UI;
namespace JianCaiWeb.Utils
{
public class DataBasePageAdapter : System.Web.UI.Adapters.PageAdapter
{
public override PageStatePersister GetStatePersister()
{
if (Page.EnableViewState == true)
return new DatabasePageStatePersister(Page);
else
return base.GetStatePersister();
}
}
}
using System;
using System.Collections.Generic;
using System.Text;
using System.Web.UI;
namespace JianCaiWeb.Utils
{
public class DataBasePageAdapter : System.Web.UI.Adapters.PageAdapter
{
public override PageStatePersister GetStatePersister()
{
if (Page.EnableViewState == true)
return new DatabasePageStatePersister(Page);
else
return base.GetStatePersister();
}
}
}
我们还需要在应用程序浏览器目录App_Browsers,然后在其中建立浏览器文件,文件的内容如下:
<!--
可在 <windir>\Microsoft.NET\Framework\<ver>\CONFIG\Browsers 中找到现有的浏览器定义
-->
<browsers>
<browser refID="Default" >
<controlAdapters>
<adapter
controlType="System.Web.UI.Page"
adapterType="JianCaiWeb.Utils.DataBasePageAdapter" />
</controlAdapters>
</browser>
</browsers>
可在 <windir>\Microsoft.NET\Framework\<ver>\CONFIG\Browsers 中找到现有的浏览器定义
-->
<browsers>
<browser refID="Default" >
<controlAdapters>
<adapter
controlType="System.Web.UI.Page"
adapterType="JianCaiWeb.Utils.DataBasePageAdapter" />
</controlAdapters>
</browser>
</browsers>