一、首先谈一下服务器端 ViewState 的好处和弊端
1.服务器端 ViewState 的好处
1).避免了网络故障带来的 ViewState 传输错误问题
2).避免了浏览器版本带来的 HiddenFiled 大小限制的问题
3).减少了传送至客户端的页面大小——因为 ViewState 存储在服务器
2.服务器端 ViewState 的弊端
1).占用大量的服务器端硬盘空间
二、服务器端 ViewState 的具体实现
建立一个继承自 System.Web.UI.Page 的 XViewStateFilesPage 类,代码如下:
using System;
using System.IO;
using System.Text;
using System.Web.UI;
![](/Images/OutliningIndicators/None.gif)
namespace XanaduSoft.Web.UI
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](/Images/OutliningIndicators/ContractedBlock.gif)
{
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
/// 将 ViewState 存储在服务器磁盘上的 Page。
/// </summary>
public class XViewStateFilesPage : Page
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
private const string m_strFilePathFormat = "~/PersistedViewState/{0}.vs.resource";
private const string m_strViewStateHiddenFieldName = "__ViewStateGuid";
private string m_strNewGuid = Guid.NewGuid().ToString();
![](/Images/OutliningIndicators/InBlock.gif)
private void WirteViewStateToFile(StringWriter SW)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
string strViewStateFilePath = MapPath(string.Format(m_strFilePathFormat,m_strNewGuid));
try
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
using (StreamWriter objStreamWriter = File.CreateText(strViewStateFilePath))
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
objStreamWriter.Write(SW.ToString());
}
}
catch (Exception exp)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
if (exp is DirectoryNotFoundException)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
Directory.CreateDirectory(strViewStateFilePath.Substring(0,strViewStateFilePath.LastIndexOf(@"\")));
WirteViewStateToFile(SW);
}
else
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
throw exp;
}
}
}
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
/// 重写 SavePageStateToPersistenceMedium 方法,保存 ViewState 到服务器磁盘
/// </summary>
/// <param name="viewState">object 的一个实例</param>
protected override void SavePageStateToPersistenceMedium(object viewState)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
// serialize the view state into a base-64 encoded string
LosFormatter objLosFormatter = new LosFormatter();
using (StringWriter objStringWriter = new StringWriter())
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
// save the view state to disk
objLosFormatter.Serialize(objStringWriter,viewState);
WirteViewStateToFile(objStringWriter);
}
// saves the view state GUID to a hidden field
Page.RegisterHiddenField(m_strViewStateHiddenFieldName,m_strNewGuid);
}
![](/Images/OutliningIndicators/InBlock.gif)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
/// 重写 LoadPageStateFromPersistenceMedium 方法,从服务器磁盘读取 ViewState
/// </summary>
/// <returns></returns>
protected override object LoadPageStateFromPersistenceMedium()
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
string strViewStateFilePath = MapPath(string.Format(m_strFilePathFormat,Request.Form[m_strViewStateHiddenFieldName]));
// deserialize the base-64 encoded string into a view state
if (!File.Exists(strViewStateFilePath))
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
throw new Exception("保存 Viewstate 的文件 \"" + strViewStateFilePath + "\" 不存在");
}
else
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
// instantiates the formatter and opens the file
LosFormatter objLosFormatter = new LosFormatter();
StreamReader objStreamReader = File.OpenText(strViewStateFilePath);
string strViewState = objStreamReader.ReadToEnd();
objStreamReader.Close();
return objLosFormatter.Deserialize(strViewState);
}
}
}
}
三、“服务器端 ViewState”方案的实施
只要是项目中的所有页面都继承自 XanaduSoft.Web.UI.XViewStateFilesPage 即可。之后在项目的根目录下会自动创建一个 PersistedViewState 文件夹用于保存各个页面的 ViewState。
四、对于“占用大量的服务器端硬盘空间”的解决方案
对于服务器端 ViewState 占用过多服务器端硬盘空间的问题。我们可以有两种解决方法:
- 定期手动删除
- 创建 HttpModules 用于定期删除 ViewState 文件,代码如下:
using System;
using System.IO;
using System.Web;
using System.Threading;
![](/Images/OutliningIndicators/None.gif)
namespace XanaduSoft.Web.HttpModules
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](/Images/OutliningIndicators/ContractedBlock.gif)
{
public class XViewStateFilesCleanUpHttpModule : IHttpModule
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
// this marks whether the clean-up code has exeucted or not
private static bool m_bIsNeedRunning = true;
// this marks the path that contain the view state files
private static string m_strCleanUpPath = HttpContext.Current.Server.MapPath("~/PersistedViewState/");
// this value is an equivelant of 2 days
private static TimeSpan tsDaysToLeaveFiles = new TimeSpan(2,0,0,0);
![](/Images/OutliningIndicators/InBlock.gif)
private static void CleanUp()
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
while (true)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
foreach (string strFilePath in Directory.GetFiles(XViewStateFilesCleanUpHttpModule.m_strCleanUpPath))
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
FileInfo objFileInfo = new FileInfo(strFilePath);
if (DateTime.Now.Subtract(objFileInfo.LastAccessTime) >= XViewStateFilesCleanUpHttpModule.tsDaysToLeaveFiles)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
objFileInfo.Delete();
}
}
Thread.Sleep(XViewStateFilesCleanUpHttpModule.tsDaysToLeaveFiles);
}
}
![](/Images/OutliningIndicators/InBlock.gif)
![](/Images/OutliningIndicators/ContractedSubBlock.gif)
IHttpModule 必须实现的成员#region IHttpModule 必须实现的成员
public void Init(HttpApplication context)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
if (XViewStateFilesCleanUpHttpModule.m_bIsNeedRunning)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
// creates a new background thread to run the clean-up code.
Thread objThread = new Thread(new ThreadStart(CleanUp));
// starts the background thread
objThread.Start();
// signals that the clean-up code has exeucted, reset m_dtLastExecuteTime
XViewStateFilesCleanUpHttpModule.m_bIsNeedRunning = false;
}
}
![](/Images/OutliningIndicators/InBlock.gif)
public void Dispose()
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
}
#endregion
}
}
编译命令行
csc /target:library /optimize /out:D:\XanaduSoft.Web.HttpModules.dll D:\XViewStateFilesCleanUpHttpModule.cs
应用方法(在Web.config中添加一下代码)
<httpModules>
<add name="ssafrs" type="XanaduSoft.Web.HttpModules.XViewStateFilesCleanUpHttpModule,XanaduSoft.Web.HttpModules" />
</httpModules>