`
jandroid
  • 浏览: 1883987 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

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

 
阅读更多

如何在传统 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.NET 实现
ASP 实现 ASP 实现
演示程序 演示程序
在现有的 ASP 应用程序中嵌入 COM 对象 在现有的 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

源于:http://msdn.microsoft.com/zh-cn/library/aa479313.aspx

分享到:
评论

相关推荐

    如何在ASP和ASP.NET中共享会话状态

    如何在ASP和ASP.NET中共享会话状态,马文婕,李娜,ASP.NET的出现大大提高了编写的站点的性能,但传统的ASP技术也需要同时应用,两种技术间会话状态的共享是必须解决的问题。文章即对�

    asp和asp.net共享Session

    使用隐藏框架的方式实现Session共享.绝对的安全, login.asp页面为主页面, 不管是查看页面源文件还是url都不会泄密,很安全的.

    asp.net不同应用程序Session共享

    asp.net 应用程序,通过web.config 应用程序发布到IIS上,实现不同应用程序之间session 共享

    ASP.NET4高级程序设计第4版 带目录PDF 分卷压缩包 part1

    1.2.1 ASP.NET1.0和ASP.NET1.1 1.2.2 ASP.NET2.0 1.2.3 ASP.NET3.5 1.2.4 ASP.NET4 1.2.5 Silverlight 1.3 总结 第2章 Visual Studio 2.1 Visual Studio 2.1.1 网站和Web项目 2.1.2 创建无项目...

    ASP.NET4高级程序设计(第4版) 3/3

    1.2.1 ASP.NET1.0和ASP.NET1.1 9 1.2.2 ASP.NET2.0 9 1.2.3 ASP.NET3.5 10 1.2.4 ASP.NET4 12 1.2.5 Silverlight 14 1.3 总结 15 第2章 Visual Studio 16 2.1 Visual Studio 16 2.1.1 网站和Web...

    ASP.NET中在不同的子域中共享Session的具体方法

    今天遇到了这个问题,于是研究了一下。要解决这个问题,首先就要明白一些Session的机理。Session在服务器是以散列表形式存在的,我们都知道Session是会话级的,每个用户...我们可以通过ASP.NET来打印出SessionID,如下

    ASP.NET.4揭秘 卷2

    n112 视图状态和控件状态 n1121 支持视图状态 n1122 支持控件状态 n113 处理回传数据和事件 n1131 处理回传数据 n1132 处理回传事件 n114 使用控件属性集合 n1141 使用ParseChildren特性 n1142 使用...

    C#.NET网络编程.part1

    基于asp.net的网络编程 3.1 webforms 3.1.1 创建第一个web窗体 3.1.2 在web窗体上添加控件 3.1.3 将控件与数据绑定 3.1.4 webforms的事件响应 3.2 服务器端控件 3.3 自定义控件 3.3.1 创建...

    计算机设计开题报告范文.docx

    ASP.NET提供了外部会话状态(External Session State)来提供内置式Web Farm的支持。另外,由于请求的各组件相互间经过了充分的优化,所以速度很快。 (4)ASP.NET还提供更多的其他方面的新特性,例如: l 内置的对象...

    计算机设计开题报告范文(1).docx

    ASP.NET提供了外部会话状态(External Session State)来提供内置式Web Farm的支持。另外,由于请求的各组件相互间经过了充分的优化,所以速度很快。 计算机设计开题报告范文(1)全文共10页,当前为第2页。 (4)ASP.NET...

    BSQL Hacker v0.9.0.9 中文汉化版

    BSQL Hacker v0.9.0.9中文汉化绿色版 ...某时的会话标记或者asp.net状态查看能够绕过通过代理页面等而被单独登陆会话使用。 这个软件仍然是一个试用版,已知问题 1,MySQL自动攻击是实验性的,有时可能不会正常工作。

    TemplateV2.Razor:使用ASP.NET Core 3.1 + Razor Pages的小型企业应用程序的管理模板

    用户旅程(会话) 建筑学 用构建 专注于关注点分离的 将MVC 6与最新版本的Visual Studio 2019和 UI验证与后端验证共享(客户端只能执行基本规则) 启用了C#8.0可空引用(.NET Standard 2.1) 数据库 数据库项目...

    Vurderingssystem:APP2000的原型

    在asp.net上发布div信息 会话重定向(如果您无权访问该页面) 让我的科目 发表我的评论 主题页尝试catch-除以零-如果数据库为空 修复轮毂条中的间隙 设置页面大小 会话超时通知? 欢迎页面可以是我的主题...

    Greater-File-Share:将网站共享为应用程序

    由ASP.NET Core托管的网站 通过直接文件地址 通过WCF服务(net.tcp://) Web API(支持Swagger) 生成共享会话的QR码 共享多个文件夹 支持自定义内容类型 开发环境设置 注意:您必须安装Windows 10 SDK才能支持...

    JAVA面试题最全集

    9.Java中访问数据库的步骤,Statement和PreparedStatement之间的区别。 10.找出下列代码可能存在的错误,并说明原因: 二、JSP&Servlet技术 1.描述JSP和Servlet的区别、共同点、各自应用的范围 2.在Web开发中...

    基于J2EE框架的个人博客系统项目毕业设计论文(源码和论文)

    随着博客人数的增加, Blog 作为一种新的生活方式、新的工作方式、新的学习方式已经被越来越多的人所接受,并且在改变传统的网络和社会结构:网络信息不再是虚假不可验证的,交流和沟通更有明确的选择和方向性,单一...

    JAVA上百实例源码以及开源项目

    FTP的目标是:(1)提高文件的共享性(计算机程序和/或数据),(2)鼓励间接地(通过程序)使用远程计算机,(3)保护用户因主机之间的文件存储系统导致的变化,(4)为了可靠和高效地传输,虽然用户可以在终端上...

    JAVA上百实例源码以及开源项目源代码

    FTP的目标是:(1)提高文件的共享性(计算机程序和/或数据),(2)鼓励间接地(通过程序)使用远程计算机,(3)保护用户因主机之间的文件存储系统导致的变化,(4)为了可靠和高效地传输,虽然用户可以在终端上...

Global site tag (gtag.js) - Google Analytics