使用 Web 服务进行 ASP 到 ASP.NET Session 桥接






4.87/5 (22投票s)
2004年3月9日
13分钟阅读

293353

2099
使用 Web 服务进行 ASP 到 ASP.NET Session 桥接
引言
本文介绍了一种使用简单的 Web 服务将现有 ASP 应用程序的会话管理迁移到 ASP.NET 的可能解决方案。对于当前由于内存中会话使用而强制执行服务器亲和性的现有 ASP Web 场,此解决方案可能很实用,并为逐步升级到 ASP.NET 提供了一种策略。
背景
(如果您了解所有这些并且只想跳到代码,请单击 此处)(如果您只想知道这会运行得多慢,请单击 此处)
现有的 ASP 应用程序经常使用“ASP Session”,这是经典 ASP 中内置的一项功能,允许数据临时存储在 Web 服务器的内存中。众所周知的限制是 ASP Session 状态是特定于机器的。对于大型解决方案,很可能使用多个 Web 服务器,并将请求定向到 Web 场中的任何 Web 服务器,因此任何内存中的 Session 状态都不会自动跟随后续请求。每个 ASP 服务器都提供自己的 Session 状态,除非用户很幸运并且碰巧返回到同一服务器,否则 Session 状态将丢失。
解决内存中 ASP Session 引起的服务器亲和性问题的一种方法是使用服务器管理产品(如 BigIP)将用户强制回 Web 场中的同一台服务器。实现此目的的一种方法是使用客户端工作站上的 cookie,服务器管理器会使用此 cookie 在每次请求时将用户重定向回同一台服务器。这可能会限制可扩展性,增加维护水平,并且由于服务器故障(例如,如果服务器发生故障,会话将丢失)而导致出错的风险更高。
ASP.NET 最终解决了这些问题,允许我们将 Session 信息存储在单个 Web 服务器之外,并存储在中央数据库或状态服务器上。太棒了,问题解决了。呃,但是现有的 ASP 代码库中的巨额投资呢?全部抛弃,然后在 .NET 中重新开始?
与其尝试向您的利益相关者推销重写所有内容为 ASP.NET 的“大爆炸”方法,不如提供一种迭代迁移代码到新模型的方法,作为正常生命周期的一部分。因此,在这一过程中,旧的 ASP 代码和新的 ASP.NET 代码能够共享一个通用的 Session 状态将非常有帮助。您管理风险,并有望保住工作。
有几种解决方案可以想到,并且可以作为经典 ASP Session 中服务器亲和性问题的战略解决方案,包括:
- 自定义组件或 ASP/ADO 脚本直接读/写到自定义 Session 数据库实现
- 自定义组件直接访问 ASP.NET Session 数据库
- 使用 Web 服务和 ASP.NET 内置 Session 进行 ASP 到 ASP.NET Session 桥接
在本文中,我们将重点关注最后一种选择,尽管也会触及每种选择的缺点(如性能)和优点。我们还将包含一些基本的性能数据,以比较 Web 服务、ASP/ADO 到自定义数据库和内存中 ASP Session 解决方案,以便您可以了解为了您选择的解决方案而牺牲了什么。
ASP 到 ASP.NET 桥接 / Web 服务解决方案
此解决方案避免了数据库 Session 实现的需要,甚至不假定状态存储在数据库中(因此您可以使用状态服务器,甚至内存中 Session)。我们只需通过 Web 服务实现一个从 ASP 到 ASP.NET 的简单桥接。如果您确实想使用中央数据库(最有可能的情况),那么这是 ASP.NET 应用程序配置(web.config 和 ASPState 数据库)的一个简单部分。
用于设置和获取 Session 数据的这些方法的代码将驻留在必须存储在 ASP 应用程序本地的 JavaScript 文件中。JavaScript 函数使用 MSXML HTTP 函数执行对 ASP.NET Web 服务的服务器端调用,并负责将 cookie 传递回用户工作站,以便整个机制能够正常工作。
优点
- 支持 Web 场部署,无需服务器亲和性,可提高可扩展性
- 实现简单,策略性地利用通用的 ASP.NET Session 状态
- 与 Session 管理松散耦合(无连接的 HTTP 接口,端口 80,可防火墙等)
- 使用经过充分测试的 ASP.NET Session 实现
缺点
- 比内存中 ASP Session 和自定义数据库实现慢得多
固有的 ASP 机制
Session 状态位于 Web 服务器内存中,其形式为字典或哈希表(例如,键值对),可以在用户会话期间设置和读取。ASP 通过向客户端提供一个在会话开始时分配给用户的唯一密钥来维护 Session 状态。此密钥存储在 HTTP cookie 中,客户端在每次请求时将此 cookie 发送给服务器。然后,服务器使用 cookie 中的密钥,并知道为任何特定请求使用哪个 Session 状态。
ASP 中用于维护 Session 状态的内置机制具有一些明显的优点,即速度和易用性。所有 Session 数据都存储在与正在执行的 ASP 相同的服务器上,因此由于不必经过网络跳数,速度非常快。然而,如前所述,将数据存储在同一台服务器上也有一个主要缺点,即迫使用户返回到同一台服务器以检索 Session 数据。这在 Web 场环境中引入了服务器亲和性的需求,从而削弱了低成本横向扩展策略的优势——您希望在需要时通过添加廉价服务器来增加可扩展性。
优点
- 快速访问内存中的 Session 信息
- 使用标准的 ASP 代码库
- 使用经过充分测试的 ASP Session 实现
缺点
- 在 Web 场中横向扩展的能力有限(服务器亲和性)
- 服务器故障对用户可见,因为会话丢失
- 利用 Web 服务器上的内存(小占用空间好,大占用空间坏)
ASP/ADO 到数据库解决方案
此方法不将 Session 数据存储在同一服务器上,而是建立 ASP 应用程序服务器与数据库服务器之间的数据库连接。这允许将数据存储在与执行 ASP 应用程序的服务器分开的中央数据库或数据库群集中。由于我的解决方案已集成到更大的专有会话管理解决方案中,因此不包含此方面的代码。
设置和获取 Session 数据的代码也可以驻留在 JavaScript 文件中,该文件支持与 Web 服务解决方案相同的方法,允许 ASP 通过替换 JavaScript include 文件来使用任一选项。除了使用自定义数据库架构外,还可以考虑直接访问 ASP.NET Session 数据库(例如 ASPState)。
优点
- 支持 Web 场部署,无需服务器亲和性
- 比 ASP.NET Web 服务接口快
缺点
- 维护自定义 Session 实现的代码
- 比内存中 ASP Session 接口慢
- 需要从 Web 服务器到数据库的数据库连接
性能
<免责声明>此处发布的结果是我在几台相当不错的 Windows 2000 Web 服务器上,通过 SQL Server 2000 数据库群集运行的一些简单性能测试。显然,如果您在 fullerdata.com 上运行在线演示,您将获得不同的结果 - 请不要滥用此在线演示,否则我可能会因 ISP 带宽限制(以及养家糊口的需要!:-) 而不得不将其关闭。所以,基本上,在您自己的环境中运行您自己的严肃性能测试。</免责声明>
使用讨论的解决方案之一,特别是 ASP/ADO 到数据库解决方案或 ASP/ASP.NET Web 服务解决方案,确实会带来额外的性能考虑。内存中 ASP Session 由于 Session 数据存储在每个 Web 服务器本地,因此在获取和设置键值对方面非常快速。任何将数据存储在单独服务器/数据库上的解决方案都会带来额外的成本,主要是连接数据库,然后通过更复杂的接口传输信息。ASP.NET / Web 服务解决方案增加了通过 HTTP 调用 Web 服务的额外成本,而 Web 服务又使用了 ASP.NET 数据库 Session。
提出的这两个解决方案在单用户速度方面都无法与内存中 ASP Session 相提并论。然而,虽然内存中 Session 对少量用户来说很快,但 Web 服务器的内存是按用户使用的,因此对于更高的流量,性能会下降。这就像比较短跑运动员和马拉松运动员一样,您可以通过将大量信息放入每个用户的 Session 来使应用程序对少量用户做出非常快速的响应。然而,一旦用户数量增加,Web 服务器的可用内存变得紧张,那么您基本上在起跑线上看起来不错,然后就因心脏病发作而死亡。:-)
为了最大限度地减少访问 Session 的往返成本,提供了通过一次调用获取和设置多个键值对的方法。这最大限度地减少了与数据库的网络连接数量或对 Web 服务的 HTTP 请求数量。这对于 Web 服务解决方案尤其重要,因为获取/设置的成本将很高,因为 HTTP 请求的开销很大。
下表中的数据提供了对每种解决方案预期性能的高级别指示。它测量了获取或设置五个键值对的最后一个字节时间(TTLB)。Microsoft Web Application Stress Tool 用于执行测试,压力级别为 25 个线程,持续一分钟。
方法 | 获取数据(毫秒) | 设置数据(毫秒) | ||
5 个值 | 1 个值 | 5 个值 | 1 个值 | |
内存中 ASP Session | 46 | 9 | 34 | 7 |
ASP/ASP.NET Web 服务(单独) | 4321 | 864 | 3397 | 679 |
ASP/ASP.NET Web 服务(分组) | 711 | 142 | 990 | 198 |
ASP/ADO 数据库(单独) | 346 | 69 | 841 | 168 |
ASP/ADO 数据库(分组) | 163 | 33 | 860 | 172 |
可以看出,内存中 ASP Session 的性能优于 ADO 和 ASP.NET / Web 服务数据库 Session 解决方案。通过使用分组方法访问 Session,可以显著抵消这一点,因为往返的成本更高。虽然 Web 服务方法比直接数据库解决方案慢,但其差异并没有人们预期的那么大(对于分组获取,慢一倍)。
使用代码
固有的 ASP
在您的 ASP 应用程序中可能正在使用的内置 ASP Session 的使用看起来会像这样:
Session("Sky") = "Blue";
在后续页面中,将读取这些值,应用程序将可以访问这些值。
var skyString = Session("Sky");
新 API 语法
需要使用以下语法而不是普通的 ASP Session 语法,以便使用封装 Session 桥接的 JavaScript 函数。
设置一个键值对
在设置一个键值对的 Session 数据时,语法将与上面内置 ASP Session 的当前语法非常相似。以下代码将替换当前使用固有 ASP Session 的代码。
设置 Session 数据
SetSessionValue("Sky", "Blue");
获取 Session 数据
var SkyString = GetSessionValue("Sky");
当在单个 ASP 中设置或检索的键值对相对较少(三个或更少)时,建议使用此方法。
设置多个键值对
上述方法的成本是,每次设置或检索一个键值对时,都会进行一次到 Web 服务的往返。鉴于这在响应时间方面可能是一项相对昂贵的操作,因此建议在 ASP 中设置或检索大量(超过 3 个)键值对时使用以下方法。
设置 Session 数据
var sessionInfo = NewSession();
sessionInfo.Add(“Sky”, "Blue");
sessionInfo.Add(“Grass”, “Green”);
.
.
.
SetSession(sessionInfo);
获取 Session 数据
var sessionInfo = GetSession();
var skyString = sessionInfo.Item(“Sky”);
var grassString = sessionInfo.Item(“Grass”);
.
.
.
JavaScript 示例
<%@ Language="JScript" %>
<script language="JScript" runat="server" src="ASPSessionWS.js" />
<%
var sessionInfo = NewSession();
sessionInfo.Item("Sky") = "Blue";
sessionInfo.Item("Grass") = "Green";
SetSession(sessionInfo);
var retrievedSession = GetSession();
var sSky = retrievedSession.Item("Sky");
var sGrass = retrievedSession.Item("Grass");
Response.Write(sSky + "<br>");
Response.Write(sGrass + "<br>");
%>
Visual BASIC 示例
<%@ Language="VBSCRIPT" %>
<script language="JScript" runat="server" src="ASPSession.js" />
<%
Dim sessionInfo
Set sessionInfo = NewSession()
sessionInfo.Item("Sky") = "Blue"
sessionInfo.Item("Grass") = "Green"
SetSession(sessionInfo)
Dim retrievedSession
Set retrievedSession = GetSession()
Dim sSky
sSky = retrievedSession.Item("Sky")
Dim sGrass
sGrass = retrievedSession.Item("Grass")
Response.Write(sSky & "<br>")
Response.Write(sGrass & "<br>")
%>
Web 服务实现
Web 服务包含四个简单的方法,支持在 ASP.NET Session 中获取/设置单个值,以及通过 XML 负载获取/设置一组 Session 变量的稍微(但差别不大)复杂的方法。
public string getSessionValue(string sessionVariable)
public bool setSessionValue(string sessionVariable, string sessionValue)
public string getSessionValues()
public bool setSessionValues(string xmlSessionValues)
为了使 ASP.NET Web 服务支持 Session 的创建和维护,每个方法都包含以下属性。这将在响应中返回 ASP.NET_SessionId cookie,可用于将 Session 桥接到 ASP 代码。
[WebMethod(EnableSession=true)]
差不多就是这样了。您可能想包含更复杂的实现来将其他服务器端状态信息集成到相同的接口中。此版本的 Web 服务也没有任何身份验证或其他使用限制,考虑到 Web 服务的开放性质,这可能不适合您的环境 - 因此,您可能希望将 GUID 或其他标识作为每个 Web 服务接口的参数,以表明用户已登录。简单易用。
ASP 桥接实现
桥接的 ASP 端基本上依赖于 MSXML2.ServerXMLHTTP COM 接口来执行对 Web 服务的服务器端调用,以及 Scripting.Dictionary 来提供一个哈希表,用于维护 Session 的临时(页面生命周期)副本。在调用 Web 服务之前,确保如果客户端工作站上已有 ASP.NET_SessionId cookie,则将其作为服务器端 Web 服务请求的一部分进行传递非常重要。同样,从 Web 服务接收到的任何 cookie 都应包含在 ASP 响应中,以便写入客户端工作站以供后续请求使用。
var xmlHTTP = Server.CreateObject("MSXML2.ServerXMLHTTP");
xmlHTTP.open("POST", sURL, false);
var clientCookie = "" + Request.Cookies("ASP.NET_SessionId");
xmlHTTP.setRequestHeader("cookie", "ASP.NET_SessionId=" +
clientCookie + "; path=/;");
.
.
.
Response.Cookies("ASP.NET_SessionId") = httpCookie;
字典对象用于转换到和从简单的 XML 负载(基本上只是一系列 <SessionItem> 节点)。
var dctSession = new ActiveXObject("Scripting.Dictionary");
var re = new RegExp("<SessionItem ", "g");
因此,也许不是最优雅的实现,但它充分利用了 ASP 中可用的功能,而无需自己编写组件。再次,简单易用。
部署
必须将名为“ASPSessionWS.js”的 JavaScript 文件复制到运行 ASP 应用程序的位置。在任何使用 ASP.NET Session 的 ASP 文件中包含此脚本标签。
<script language="”Jscript”" runat="”server”" src=”\Script\ASPSessionWS.js” >
</script>
Web 服务器只需要具有端口 80 的访问权限,以及您复制 Web 服务的位置的 URL,并在该脚本文件中进行更新(如下所示)。Web 服务的部署只是将您的 .asmx 文件复制到将维护 Session 状态的 Web 服务器,然后后者需要更改 web.config 文件以反映您部署数据库的位置(MSDN 在此处有相关教程)。
function GetWebService(Function, Parameters)
{
var xmlPayload = "";
var sURL = "http://www.fullerdata.com/ASPBridge/bridge.asmx" + "/" +
Function;
摘要
使用 Web 服务作为从旧版 ASP Session 到新版 ASP.NET Session 的桥接,为迁移应用程序到新技术提供了一种实用的方法,允许旧版和新版共享单个 Session 上下文。性能成本很高,但可能是一个“足够好”的解决方案,作为完全迁移到 .NET 的过渡方案,尤其是在 Web 场环境中,在那里消除 Web 服务器亲和性是优先事项。
链接
CodeProject 上已经有许多关于使用 ASP.NET Session 状态的文章,其中以下文章值得注意( IMHO):
MSDN 上有一些关于 ASP.NET Session 的优秀文章,绝对值得一读。
历史
- 2004 年 3 月 - 代码部署到 FullerData.com 并将文章提交到 CodeProject.com