如何在传统 ASP 和 ASP.NET 之间共享会话状态
发布日期 : 4/1/2004| 更新日期 : 4/1/2004

Billy Yuen

Microsoft Corporation

2003 年 2 月

适用于:

Microsoft ASP.NET

摘要:讨论如何利用 Microsoft .NET 框架类和 .NET 框架的序列化特性,以便在传统 ASP 和 Microsoft ASP.NET 之间共享会话状态。通过共享会话状态,就允许在并行运行现有的 ASP 应用程序和 ASP.NET 应用程序的同时,分阶段地将 ASP 应用程序转换为 ASP.NET 应用程序。(12 页打印页)

下载本文的源代码。

本页内容

简介
概念综述
ASP.NET 实现
ASP 实现
演示程序
在现有的 ASP 应用程序中嵌入 COM 对象
局限性/改进
小结

简介

Microsoft ASP.NET 是最新的 Microsoft 技术,用于开发基于 Web 的应用程序。相比传统的 ASP 脚本技术而言,它具有很多优点,其中包括:1) 将 UI 表示形式从业务逻辑中分离出来,从而提供更好的开发结构; 2) 其代码是完全编译的,而在传统 ASP 中代码是解释的;和 3) 其编译特性结合其高速缓存支持,就意味着相对用传统 ASP 编写的等效站点而言,使用 ASP.NET 编写的站点的性能有显著提高。

尽管将现有的 ASP 应用程序转换到 ASP.NET 具有潜在的益处,但很多现有的 ASP 应用程序都具有关键的使命并且是相当复杂的。这种转换过程可能需要大量资源,并可能给现有的应用程序带来额外的风险。要解决这些问题,一种方法就是同时运行 ASP 和 ASP.NET,并一次只将应用程序的一部分转换为 ASP.NET。为了同时运行新的和旧的应用程序,就需要一种机制在传统 ASP 和 ASP.NET 之间共享会话状态。在本文中,我将讨论如何利用 Microsoft.NET 框架的若干类和序列化特性来共享这些会话状态。

返回页首

概念综述

Cookie 是 Web 应用程序用来标识用户会话的最常用方法,可供传统 ASP 和 ASP.NET 二者用来标识会话状态。而用 ASP 脚本将会话状态信息存储在内存中,且不能与其他应用程序(如 ASP.NET)共享。如果会话状态以一种通用格式存储在 Microsoft SQL Server 中,则传统的 ASP 和 ASP.NET 都能访问会话状态。

在此示例中,使用了一个名为 mySession 的 cookie 来标识用户会话。当用户向 Web 应用程序发出请求时,该用户将被发放一个唯一的 cookie 以便标识该会话。在后续的请求中,浏览器将该唯一的 cookie 发送回服务器以标识该会话。在加载所请求的 Web 页面之前,一个自定义的对象将利用该唯一 cookie 从 SQL Server 中重新加载用户会话数据。在 Web 页面中通过该自定义的对象即可访问会话状态。在 Web 请求结束后,随着该请求的终止,会话数据将被保存回 SQL Server 中(参见图 1)。

1. 示例数据流
返回页首

ASP.NET 实现

在 ASP.NET 中,每个 Web 页面都是从 System.Web.UI.Page 类派生出来的。Page 类中包含 HttpSession 对象的一个实例以用于会话数据。在本示例中,从 System.Web.UI.Page 派生了一个名为 SessionPage 的自定义 Page 类,以实现与 Page 类完全相同的各种特性。派生页的唯一不同之处就是利用一个自定义的会话对象重写了默认的 HttpSession。(利用实例变量的 new 修饰符,C# 允许派生类隐藏基类的成员。)

   public class SessionPage : System.Web.UI.Page
{
...
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[name.ToLower()];
}
set
{
dic[name.ToLower()] = value;
}
}
}

Page 类公开不同的事件和方法以供进行自定义。特别地,OnInit 方法用于设置 Page 对象的初始化状态。如果该请求不具有 mySession cookie,则将给请求者发放一个新的 mySession cookie。否则,将利用一个自定义的数据访问对象(SessionPersistence)从 SQL Server 中检索会话数据。dsn 和 SessionExpiration 值是从 web.config 中检索的。

      override protected void OnInit(EventArgs e)
{
InitializeComponent();
base.OnInit(e);
}
private void InitializeComponent()
{
cookie = this.Request.Cookies[sessionPersistence.SessionID];
if (cookie == null)
{
Session = new mySession();
CreateNewSessionCookie();
IsNewSession = true;
}
else
Session = sessionPersistence.LoadSession(
Server.UrlDecode(cookie.Value).ToLower().Trim(),
dsn,
SessionExpiration
);
this.Unload += new EventHandler(this.PersistSession);
}
private void CreateNewSessionCookie()
{
cookie = new HttpCookie(sessionPersistence.SessionID,
sessionPersistence.GenerateKey());
this.Response.Cookies.Add(cookie);
}

为了获得最佳性能,SessionPersistence 类利用 Microsoft .NET 框架的 BinaryFormatter,以二进制格式对会话状态进行序列化和反序列化。随后,可以将所得到的二进制会话状态数据以 art 字段类型存储在 SQL Server 中。

      public  mySession LoadSession(string key, string dsn,
int SessionExpiration)
{
SqlConnection conn = new SqlConnection(dsn);
SqlCommand LoadCmd = new SqlCommand();
LoadCmd.CommandText = command;
LoadCmd.Connection = conn;
SqlDataReader reader = null;
mySession Session = null;
try
{
LoadCmd.Parameters.Add("@ID", new Guid(key));
conn.Open();
reader = LoadCmd.ExecuteReader();
if (reader.Read())
{
DateTime LastAccessed =
reader.GetDateTime(1).AddMinutes(SessionExpiration);
if (LastAccessed >= DateTime.Now)
Session = Deserialize((Byte[])reader["Data"]);
}
}
finally
{
if (reader != null)
reader.Close();
if (conn != null)
conn.Close();
}
return Session;
}
private mySession Deserialize(Byte[] state)
{
if (state == null) return null;
mySession Session = null;
Stream stream = null;
try
{
stream = new MemoryStream();
stream.Write(state, 0, state.Length);
stream.Position = 0;
IFormatter formatter = new BinaryFormatter();
Session = (mySession)formatter.Deserialize(stream);
}
finally
{
if (stream != null)
stream.Close();
}
return Session;
}

当该请求结束时,将激发 Page 类的 Unload 事件,注册用于 Unload 事件的事件处理程序将会话数据序列化成二进制格式,并将所得的二进制数据保存到 SQL Server 中。

      private void PersistSession(Object obj, System.EventArgs arg)
{      sessionPersistence.SaveSession(
Server.UrlDecode(cookie.Value).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();
SaveCmd.Connection = conn;
try
{
if (IsNewSession)
SaveCmd.CommandText = InsertStatement;
else
SaveCmd.CommandText = UpdateStatement;
SaveCmd.Parameters.Add("@ID", new Guid(key));
SaveCmd.Parameters.Add("@Data", Serialize(Session));
SaveCmd.Parameters.Add("@LastAccessed", DateTime.Now.ToString());
conn.Open();
SaveCmd.ExecuteNonQuery();
}
finally
{
if (conn != null)
conn.Close();
}
}
private Byte[] Serialize(mySession Session)
{
if (Session == null) return null;
Stream stream = null;
Byte[] state = null;
try
{
IFormatter formatter = new BinaryFormatter();
stream = new MemoryStream();
formatter.Serialize(stream, Session);
state = new Byte[stream.Length];
stream.Position = 0;
stream.Read(state, 0, (int)stream.Length);
stream.Close();
}
finally
{
if (stream != null)
stream.Close();
}
return state;
}

SessionPage 类及其相关类都封装在 SessionUtility 程序集中。在新的 ASP.NET 项目中,将建立一个对该 SessionUtility 程序集的引用,并且为了与传统 ASP 代码共享会话,将从 SessionPage 而不是 Page 类派生出每个页面。一旦完成迁移过程,通过注释掉 SessionPage 类中的 Session 变量声明即可解除基类 HttpSession 的隐藏,从而新的应用程序可切换回使用本机的 HttpSession 对象。

返回页首

ASP 实现

本机的 ASP 会话只能将会话数据存储在内存中。为了将会话数据存储到 SQL Server 中,我们编写了一个自定义的 Microsoft Visual Basic6.0 COM 对象以管理会话状态,而不使用本机的会话对象进行管理。这个 COM 对象将在每个 Web 请求开始时得以实例化,并从 SQL Server 处重新加载会话数据。当 ASP 脚本完成时,此对象将终止,并且会话状态将被保存回 SQL Server 中。

Visual Basic 6 COM Session 对象的主要目的就是提供对 Microsoft Internet Information Server 内部对象的访问。Visual Basic 6.0 COM Session 对象使用 SessionUtility 程序集的 mySession 类来保留会话状态,并使用 SessionUtility 的 SessionPersistence 类从 SQL Server 中加载会话数据或将会话数据保存回 SQL Server。利用 regasm.exe 实用工具,mySessionSessionPersistence 类可被公开为 COM 对象。regasm.exe 实用工具能够注册并创建一个类库,以便 COM 客户端使用各个框架类。

在该对象的构造过程中,会话状态信息得以重新加载。构造函数 (class_initialize) 将首先从 Application 对象中检索会话 cookie、会话超时 (SessionTimeOut) 和数据库连接字符串 (SessionDSN),并创建 mySession 类的一个实例以持有这些会话数据。然后,构造函数将尝试利用给定的 cookie 从 SQL Server 中重新加载会话数据。如果 SQL Server 不包含相应的会话信息,或者该会话已经过期,则将发放一个新的 cookie。如果 SQL Sever 确实返回会话状态数据,则这些会话状态将被存储在 mySession 对象中。

Private Sub Class_Initialize()
On Error GoTo ErrHandler:
Const METHOD_NAME As String = "Class_Initialize"
Set mySessionPersistence = New SessionPersistence
Set myObjectContext = GetObjectContext()
mySessionID = ReadSessionID()
myDSNString = GetConnectionDSN()
myTimeOut = GetSessionTimeOut()
myIsNewSession = False
Call InitContents
Exit Sub
ErrHandler:
Err.Raise Err.Number, METHOD_NAME & ":" & Err.Source, Err.Description
End Sub
Private Sub InitContents()
On Error GoTo ErrHandler:
Const METHOD_NAME As String = "InitContents"
If mySessionID = "" Then
Set myContentsEntity = New mySession
mySessionID = mySessionPersistence.GenerateKey
myIsNewSession = True
Else
Set myContentsEntity =
mySessionPersistence.LoadSession(mySessionID, myDSNString, myTimeOut)
End If
Exit Sub
ErrHandler:
Err.Raise Err.Number, METHOD_NAME & ":" & Err.Source, Err.Description
End Sub

当该对象实例超出脚本的作用范围时,析构函数 (class_terminate) 将执行。析构函数将利用 SessionPersistence.SaveSession() 方法保持会话数据。如果这是新会话,析构函数还会向浏览器回送一个新 cookie。

Private Sub Class_Terminate()
On Error GoTo ErrHandler:
Const METHOD_NAME As String = "Class_Terminate"
Call SetDataForSessionID
Exit Sub
ErrHandler:
Err.Raise Err.Number, METHOD_NAME & ":" & Err.Source, Err.Description>
End Sub
Private Sub SetDataForSessionID()
On Error GoTo ErrHandler:
Const METHOD_NAME As String = "SetDataForSessionID"
Call mySessionPersistence.SaveSession(mySessionID,
myDSNString, myContentsEntity, myIsNewSession)
If myIsNewSession Then Call WriteSessionID(mySessionID)
Set myContentsEntity = Nothing
Set myObjectContext = Nothing
Set mySessionPersistence = Nothing
Exit Sub
ErrHandler:
Err.Raise Err.Number, METHOD_NAME & ":" & Err.Source, Err.Description
End Sub

单击本文顶部的链接,您可以下载 ASP.NET SessionUtility 项目的源代码 — COM 会话管理器和演示代码。

返回页首

演示程序

本演示程序的设计目的为递增并显示一个数字。不管加载哪个页面,该数字将总是递增,因为其数值存储在 SQL Server 中且在传统 ASP 和 ASP.NET 之间共享。

演示程序的设置步骤

  • 创建一个名为 SessionDemoDb 的新数据库。

  • 创建 SessState 表 (osql.exe –E –d SessionDemoDb –i Session.sql)。

  • 创建名为 Demo 的新虚拟目录。

  • 关闭 ASP 配置选项卡中的 ASP Session。

  • 将 web.config、testPage.aspx、Global.asa、testPage.asp 和 GlobalInclude.asp 复制到虚拟目录中。

  • 更新 Global.asa 和 web.config 中的 DSN 字符串设置。会话超时设置是可选的。默认值为 20 分钟。聽

  • 将 SessionUtility.dll 安装到 Global Assembly Cache (gacutil /i SessionUtility.dll)。

  • 利用 regasm.exe 将 SessionUtility.dll 公开为 COM 对象 (regasm.exe SessionUtility.dll /tlb:SessionUtility.tlb)。

  • 将 SessionManager.dll 复制到一个本地目录中,并利用 regsvr32.exe 注册该文件 (regsvr32 SessionManager.dll)。

  • 为 IUSR_<machine_name> 帐号赋予对 SessionMgr.dll 的读和执行权限。

演示程序的运行步骤

  • 启动 Microsoft Internet Explorer。

  • 加载传统 ASP 的 testPage.asp。Web 页面中应该显示数字 "1"。

  • 单击 Internet Explorer 上的刷新按钮,重新加载该页面。该数字应该递增。

  • 将 URL 改为 ASP.NET 版的 testPage.aspx。该数字应该继续递增。

  • 如果首先启动 testPage.aspx 页面,也可重复同样的过程。

返回页首

在现有的 ASP 应用程序中嵌入 COM 对象

在开发 ASP 应用程序时,惯例是在每个脚本的开始处包含一个文件以便共享公共代码和常量。要加入自定义的会话对象,最佳的方法就是在公共的包含文件中添加相应的实例化代码。最后一个步骤就是将对该会话对象的全部引用替换为自定义的会话变量名。

返回页首

局限性/改进

如果现有的 ASP 应用程序将一个 COM 对象存储在 Session 对象中,则此解决方案并不支持这种情况。在这种情况下,需要一个自定义的封送拆收器来序列化/反序列化各种状态,以便使用自定义的会话对象。此外,此解决方案不支持存储字符串类型数组。但只需稍加努力,我们就可利用 Microsoft Visual Basic6.0 Join 函数将所有的数组元素组合成单个字符串,然后再将其存入会话对象中,从而实现这种功能。利用 Visual Basic 6.0 Split 函数将该字符串分解成单独的数组元素即可完成反向操作。在 .NET 框架方面,JoinSplit 方法都是 String 类的成员。

返回页首

小结

ASP.NET 代表了一种全新的编程典范和结构,并且比传统的 ASP 具有更多优势。虽然从 ASP 迁移到 ASP.NET 并不是一个简单的过程,但 ASP.NET 更好的编程模型和更高的性能使得这种转换过程物有所值。除了将 COM 对象存储在 Session 对象中的情况外,本文所述的方法提供了一种解决方案,使得这种迁移过程更加简单。

关于作者

Billy Yuen 就职于北加州的 Microsoft 硅谷技术中心。此中心致力于开发 Microsoft .NET 框架解决方案。如果希望与他联系,可发送电子邮件至billyy@microsoft.com。

转入原英文页面

返回页首

转载于:https://www.cnblogs.com/MaxWoods/archive/2008/01/25/1053081.html

如何在传统 ASP 和 ASP.NET 之间共享会话状态相关推荐

  1. 基于Web Services建立Asp与Asp.Net之间Session数据桥的应用研究

    本文的目的在于提供一种可行的解决方案通过Web Service技术来整合和管理现有的Asp程序到Asp.Net. 此应用解决方案尽可能从实际出发以迭代更新方式的策略把Asp Web服务器内存中的当前S ...

  2. (转)asp和asp.net区别

    ASP(Active Server Pages)是Microsfot公司1996年11月推出的WEB应用程序开发技术,它既不是一种程序语言,也不是一种开发工具,而是一种技术框架,不须使用微软的产品就能 ...

  3. ASP与ASP.NET的区别

    师姐开始学习asp了,昨天问了我asp与asp.net的区别,结果没回答好....太丢人了... ASP(Active Server Pages)是Microsfot公司1996年11月推出的WEB应 ...

  4. 如何实现Asp与Asp.Net共享Session

    在.net中,Session的存储机制已经与Asp的存储机制不一样,虽然可以在同一个IIS下同时运行asp与aspx,但是它们之间不能传递Session.   之前大批系统应用到了asp,在升级过程中 ...

  5. Asp.net(asp,jsp)+JavaScript动态实现添加数据行

    在应用程序的开发中,有些输入信息是动态的,比如我们要注册一个员工的工作经历,比如下图 如果做成死的,只能填写三个,如果是四个呢?或者更多呢,那不是添加不上去了吗,所以这样固然不好,我们可以用动态添加表 ...

  6. ASP与ASP.NET的优势与不足

    ASP和ASP.NET是Web开发领域比较流行的动态Web开发技术. ASP(Active Server Pages)是Microsfot公司1996年11月推出的WEB应用程序开发技术,它既不是一种 ...

  7. ajax html成功 asp,AJAX ASP

    AJAX ASP AJAX 被用于创建交互性更强的应用程序. AJAX ASP 实例 下面的实例将演示当用户在输入框中键入字符时,网页如何与 Web 服务器进行通信: 实例 Start typing ...

  8. 没完没了的Cookie,读懂asp.net,asp等web编程中的cookies

    在我刚学会一点asp编程时就知道cookie了,当时照着书上的代码一通输入运行后,一切OK,就这样我自以为掌握了cookie,学javascript照样是一通代码运行成功,cookie到此为止应该是山 ...

  9. 1月4日链接篇:ASP.NET, ASP.NET AJAX, ASP.NET MVC, Visual Studio, IIS7

    [原文地址]Jan 4th Links: ASP.NET, ASP.NET AJAX, ASP.NET MVC, Visual Studio, IIS7 [原文发表日期] Friday, Januar ...

最新文章

  1. GlobalSign 荣登网络信任联盟 2013 年网络信任荣誉榜
  2. libsvm Minist Hog 手写体识别
  3. JDK的环境变量配置(步骤超级简单)
  4. c语言蜂鸣字符,蜂鸣器原理
  5. 语音识别(ASR)论文优选:自监督学习Self-Supervised Learning for speech recognition with Intermediate layer supervisi
  6. java if else 如何简化_if else 简化写法
  7. 大视角、大方向、大问题、大架构:(结局)解决问题的出发点
  8. Pytorch 如何 优化/调整 模型参数
  9. 如何通过优化物流体验的技术来提高客单价?
  10. ThinkPHP 微信支付及退款
  11. java和scala代码可以混合编写吗_IDEA实现Java与Scala代码混合开发
  12. DataGrip连接hive建表时报cannot recognize input near ‘show‘ ‘indexes‘ ‘on‘ in ddl statement错误
  13. 基于PHP的鲜花商城系统
  14. 使用 PhpStorm 来开发和 Debug Laravel Sail 项目
  15. json c语言开发,JSON c语言开发指南
  16. 阿里云学生机搭建spark、hadoop集群(踩坑之路)
  17. javascript字符串string常用的几种方法
  18. SQL过滤中文(或英文)数据
  19. 商业银行的网上银行安全技术研究与设计(转载)
  20. 一种伪DNA密码学方法

热门文章

  1. 新疆有没有教电脑编程C语言,新疆学习电脑编程,新疆学电脑编程哪里好,新疆学电脑编程效果怎么样...
  2. 超市商品摆放图片_商品摆放舍不得拿、干净又卫生的马来西亚版大润发——NSK超市...
  3. vim 快捷键_VIM学习笔记 自动补全详解(Auto-Completion Detail)
  4. php 继承性,php面向对象全攻略 (七) 继承性_php基础
  5. Cairngorm 3 libraries 简介 是通过google翻译加上自己的理解得来的
  6. Struts 常用标签的使用
  7. oracle基础入门(四)
  8. [译]理解 Node.js 事件驱动架构
  9. Centos7.X自带的防火墙和服务的相关的配置
  10. 第十章 动态选录协议