前言
ASPNET是微软提供的最新的开发基于Web的应用程序的技术它提供了大量的比传统ASP脚本技术的好处包括
)通过把UI表现层(presentation)与商业逻辑(business logic)分开建立了更好的开发结构
)使用完全编译的代码代替了传统ASP的代码翻译
)它编译特性与每个支持的方法协同这意味着使用ASPNET的站点比使用传统的ASP站点的性能更高
尽管把存在的ASP应用程序转换到ASPNET有很多潜在的好处也有些ASP应用程序任务很重要并且复杂转换过程可能需要更多资源并给应用程序带来更多风险解决这些问题的途径之一是同时运行ASP和ASPNET应用程序在一个时刻将一个对话转换为ASPNET为了同时运行新旧程序需要建立一个机制在传统的ASP与ASPNET间共享对话状态本文讨论的是怎样使用NET框架组件的类和序列化特性共享状态信息
概述
Cookie是Web应用程序识别用户对话的最常用的方法可以用于识别传统的ASP和ASPNET对话状态在ASP脚本中状态信息保存在内存中不能与其它应用程序(例如ASPNET)共享如果对话状态使用通用格式保存在微软SQL Server中它就可以被传统的ASP和ASPNET共同访问
在本例中名为mySession的Cookie用于识别用户对话当用户对Web应用程序作出请求时将为该用户产生唯一的Cookie用于识别对话在随后的请求中浏览器将该唯一的Cookie发送回服务器用来识别对话在被请求的Web页载入前一个自定义对象将使用该唯一的Cookie从SQL Server中重新载入用户对话数据通过自定义对象Web页中的对话状态是可以访问的Web请求完成后如果请求终止对话数据将保存回SQL Server(见图)
图数据流简单图 ASPNET实现
在ASPNET中每一个Web页都衍生自SystemWebUIPage类Page类集合了HttpSession对象的一个实例用于处理对话数据在本例中叫做SessionPage的自定义Page类来衍生自SystemWebUIPage提供了类似Page类的所有特性唯一的区别是默认的HttpSession使用自定义的对话对象重载了(对实例变量使用new修改符C#允许衍生的类隐藏基类的成员)
public class SessionPage : SystemWebUIPage
{
public new mySession Session = null;
}
自定义的对话类使用HybridDictionary对象来相应保存内存中的对话状态(HybridDictionary可用于处理任意数量的对话元素)为了与传统的ASP通用该自定义对话对象将限制对话数据类型为字符串型(默认的HttpSession允许对话保存任意类型的数据不能与传统的ASP通用)
[Serializable]
public class mySession
{
private HybridDictionary dic = new HybridDictionary();
public mySession()
{
}
public string this [string name]
{
get
{
return (string)dic[nameToLower()];
}
set
{
dic[nameToLower()] = value;
}
}
}
Page类为定制暴露了不同的事件和方法特别是OnInit方法用于设置Page对象的初始化状态如果请求不包含名为mySession的Cookie将为请求者产生一个新的mySession Cookie另外对话数据将使用自定义数据访问对象SessionPersistence从SQL Server中检索出来DSN和SessionExpiration的值从nfig中检索
override protected void OnInit(EventArgs e)
{
InitializeComponent();
baseOnInit(e);
}
private void InitializeComponent()
{
cookie = thisRequestCookies[sessionPersistenceSessionID];
if (cookie == null)
{
Session = new mySession();
CreateNewSessionCookie();
IsNewSession = true;
}
else
Session = sessionPersistenceLoadSession(
ServerUrlDecode(cookieValue)ToLower()Trim()
dsn
SessionExpiration
);
thisUnload += new EventHandler(thisPersistSession);
}
private void CreateNewSessionCookie()
{
cookie = new HttpCookie(sessionPersistenceSessionID
sessionPersistenceGenerateKey());
thisResponseCookiesAdd(cookie);
}
SessionPersistence类使用微软NET框架组件的BinaryFormatter来串行化和并行化对话状态为二进制格式以提供最佳性能结果的二进制对话数据接着作为图象字段类型被存入SQL Server
public mySession LoadSession(string key string dsn
int SessionExpiration)
{
SqlConnection conn = new SqlConnection(dsn);
SqlCommand LoadCmd = new SqlCommand();
LoadCmdCommandText = command;
LoadCmdConnection = conn;
SqlDataReader reader = null;
mySession Session = null;
try
{
LoadCmdParametersAdd(@ID new Guid(key));
connOpen();
reader = LoadCmdExecuteReader();
if (readerRead())
{
DateTime LastAccessed =readerGetDateTime()AddMinutes(SessionExpiration);
if (LastAccessed >= DateTimeNow)
Session = Deserialize((Byte[])reader[Data]);
}
}
finally
{
if (reader != null)
readerClose();
if (conn != null)
connClose();
}
return Session;
}
private mySession Deserialize(Byte[] state)
{
if (state == null) return null;
mySession Session = null;
Stream stream = null;
try
{
stream = new MemoryStream();
streamWrite(state stateLength);
streamPosition = ;
IFormatter formatter = new BinaryFormatter();
Session = (mySession)formatterDeserialize(stream);
}
finally
{
if (stream != null)
streamClose();
}
return Session;
}
在请求的末尾Page类的Unload事件被启动了一个同Unload事件一起注册的事件处理方法将串行化对话数据为二进制格式并将结果二进制数据存入SQL Server
private void PersistSession(Object obj SystemEventArgs arg)
{ sessionPersistenceSaveSession(
ServerUrlDecode(cookieValue)ToLower()Trim() dsn Session IsNewSession);
}
public void SaveSession(string key string dsn
mySession Session bool IsNewSession)
{
SqlConnection conn = new SqlConnection(dsn);
SqlCommand SaveCmd = new SqlCommand();
SaveCmdConnection = conn;
try
{
if (IsNewSession)
SaveCmdCommandText = InsertStatement;
else
SaveCmdCommandText = UpdateStatement;
SaveCmdParametersAdd(@ID new Guid(key));
SaveCmdParametersAdd(@Data Serialize(Session));
SaveCmdParametersAdd(@LastAccessed DateTimeNowToString());
connOpen();
SaveCmdExecuteNonQuery();
}
finally
{
if (conn != null)
connClose();
}
}
private Byte[] Serialize(mySession Session)
{
if (Session == null) return null;
Stream stream = null;
Byte[] state = null;
try
{
IFormatter formatter = new BinaryFormatter();
stream = new MemoryStream();
formatterSerialize(stream Session);
state = new Byte[streamLength];
streamPosition = ;
streamRead(state (int)streamLength);
streamClose();
}
finally
{
if (stream != null)
streamClose();
}
return state;
}
SessionPage类以及与它相关的类被封装在SessionUtility组件中在一个新ASPNET项目中需要作SessionUtility组件的引用为了与传统的ASP代码共享对话每个页面由SessionPage代替Page类衍生出来一旦移植完成了新应用程序能通过说明SessionPage类中定义的对话变量切换回使用原来的HttpSession对象来显示基本的HttpSession