Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

ASP to ASP.NET Session Bridge Using a Web Service

0.00/5 (No votes)
8 Mar 2004 44  
ASP to ASP.NET Session Bridge Using a Web Service

Introduction

This article considers a possible solution for migrating the session management of an existing ASP application into ASP.NET using a simple web service. This solution might be pragmatic for an existing ASP web farm that is currently enforcing server-affinity due to the in-memory session usage and provides a strategy for iteratively upgrading to ASP.NET.

Background

(Click Here if you know all this and just want to skip to the code)

(Click Here if you just want to know how damn slowly this would run)

Existing ASP applications often make use of �ASP sessions�, a feature built into classic ASP that allows data to be temporarily stored within the memory of the web server. The well-documented limitation is that ASP session state is machine specific. For larger solutions a number of web servers are likely to be used and requests directed to any of the web servers in the farm, therefore any in-memory session state will not automatically follow subsequent requests. Each ASP server provides its own session state and unless the user is lucky and happens to return to the same server, the session state is lost.

A solution to this server-affinity caused by in-memory ASP sessions has been to use server management products (such as BigIP) to force users back to the same server within a farm. One way in which this is achieved is by using a cookie on the client workstation, which the server manager uses to direct the user back to the same server on each request. This can limit scalability, incurs a higher level of maintenance and has a higher risk of errors due to server failures (e.g. the session is lost if the server fails).

ASP.NET finally addressed these problems and allowed us to store the session information off of the individual web servers and on a central database or state server. Wonderful, problem solved. Errrm, but what about that very large investment in the existing ASP code-base? Throw it away and start again in .NET?

Rather than try to sell a big-bang approach of re-writing everything in ASP.NET to your stakeholders, an alternative solution is to come up with an iterative method of migrating code to the new model as part of your normal lifecycle. It would therefore be very helpful if the old ASP code and the new ASP.NET code could share a common session state during this process. You manage your risk and hopefully keep your job.

There are a few solutions that come to mind and might serve as a strategic solution to this problem of server-affinity when using classic ASP sessions, which include:

  • Custom component or ASP/ADO script to read/write directly to a custom session database implementation
  • Custom component to access ASP.NET session database directly
  • ASP to ASP.NET session-bridge using web services and ASP.NET built in sessions

For this article, we will be concentrating on the last of these options, although the disadvantages (such as performance) and advantages of each will be touched upon. We will also include some basic performance figures that compare the web service, ASP/ADO to custom database and in-memory ASP session solutions, so you can get a feel for what is being traded off for your chosen solution.

ASP to ASP.NET Bridge / Web-Service Solution

This solution avoids the need for a database session implementation and does not even assume the state is stored in a database (so you could use a state server, or even a in-memory sessions). We just implement a simple bridge from ASP to ASP.NET via a web service. If you do want to use a central database (most likely scenario), then this is a simple part of the ASP.NET application configuration (web.config and ASPState database).

The code for the methods used to set and get session data will reside in a JavaScript file that must be stored locally to the ASP applications. The JavaScript functions use the MSXML HTTP functions to perform server-side calls to the ASP.NET web service and are responsible for the cookies being passed back to the user workstation in order for this whole mechanism to work.

Advantages:

  • Supports web-farm deployment without server affinity for higher scalability
  • Simple implementation making strategic use of common ASP.NET session state
  • Loosely coupled to session management (connectionless HTTP interface, port 80, can be firewalled etc)
  • Uses well-tested ASP.NET session implementation

Disadvantages:

  • Much slower interface than in-memory ASP Sessions and custom database implementations

Intrinsic ASP Mechanism

The session state is in the web-server memory and in the shape of a dictionary or hash table (e.g. key-value pairs), which can be set and read for the duration of a user session. ASP maintains session state by providing the client with a unique key assigned to the user when the session begins. This key is stored in an HTTP cookie that the client sends to the server on each request. The server then uses the key from the cookie and knows which session state to use for any particular request.

The mechanism built into ASP for maintaining session state has some clear advantages, namely speed and ease of use. All the session data is stored on the same server as the ASP that is being executed, thus it is very fast from not having to suffer any network hops. However, as mentioned earlier, storing the data on the same server also has a major disadvantage of forcing a user to return to the same server in order to retrieve session data. This introduces the need for server affinity within a web-farm environment, which lessens the advantages of a low-cost scale-out strategy - you want to bung in cheap servers to increase scaleability as needed.

Advantages:

  • Fast in-memory access to session information
  • Uses standard ASP code base
  • Uses well-tested ASP session implementation

Disadvantages:

  • Limited ability to scale-out in web farms (server affinity)
  • Server failures are visible to users due to lost sessions
  • Utilizes memory on the web-server (in terms of small footprint good, large footprint bad)

ASP/ADO to Database Solution

Rather than storing session data on the same server, this method establishes a database connection between the ASP application server and a database server. This allows data to be stored on a central database or database cluster, separate from the servers on which the ASP applications are executed. No code is included for this, given my solution is integrated into a larger proprietry session management solution.

The code to set and get session data could also reside in a JavaScript file that supports the same methods as the web-service based solution, allowing the ASP to use either option by replacing the JavaScript include file. As well as using a custom database schema, directly accessing the ASP.NET session database (e.g. ASPState) could also be considered.

Advantages:

  • Supports web-farm deployment without server affinity
  • Faster interface than ASP.NET web service

Disadvantages:

  • Maintain code for a custom session implementation
  • Slower interface than in-memory ASP Sessions
  • Requires database connections from web servers to database

Performance

<Disclaimer> The results published here are of some simple performance tests that were run on a couple of fairly decent Windows 2000 web servers, along a SQL Server 2000 database cluster. Obviously if you run the online demo on fullerdata.com, you will get different results - please don't abuse this online demo, otherwise I might have to take it down due to my ISP bandwidth limit (and the need to feed my family! :-). So basically, run your own serious performance tests in your own environment. </Disclaimer>

Using one of the solutions discussed, specifically the ASP/ADO to database solution or the ASP/ASP.NET web service solution, does present additional performance considerations. In-memory ASP Sessions are extremely fast in getting and setting key-value pairs due to the fact that the session data is stored locally on each web server. Any solution that stores the data on a separate server/database presents an extra cost, mainly in connecting to the database and then transferring information across the more complex interface. The ASP.NET / web-service solution presents a further cost of invoking the web service over HTTP, which in turn uses the ASP.NET database sessions.

The two solutions presented cannot come close to matching the single-user speed of in-memory ASP Sessions. However, whilst in-memory sessions are fast for a small number of users, web-server memory is being used per user, and thus for higher volume the performance degrades. It's like comparing a runner doing a sprint versus a marathon, in that you can make an application that responds very quickly for low number of users by placing a lot of information in each users session. However, once the number of users increases and the available memory becomes a contention for the web-server, then you basically look good off of the start line and then die of a heart attack. :-)

In order to minimize the round-trip cost of accessing sessions, methods for getting and setting multiple key-value pairs with one call have been made available. This minimizes the number of network connections to the database or HTTP requests to the web service. This is particularly important for the web-service solution, given the cost of getting/setting will be high due to the expense of an HTTP request.

The data in the table below provides a high level indication of the performance that can be expected by each of the solutions. It measures the time to last byte (TTLB) for getting or setting five key-value pairs. The Microsoft Web Application Stress Tool was used to perform the tests with a stress level of 25 threads for a one-minute duration.

Method Get Data (ms) Set Data (ms)
5 values 1 value 5 values 1 value
In-memory ASP Sessions 46 9 34 7
ASP/ASP.NET web service individually 4321 864 3397 679
ASP/ASP.NET web service grouped 711 142 990 198
ASP/ADO database individually 346 69 841 168
ASP/ADO database grouped 163 33 860 172

As can be seen, the in-memory ASP sessions performance is faster than both the ADO and ASP.NET / web service database session solutions. This can be offset significantly by accessing the session using the grouped methods given the higher cost of the round-trips. Whilst the web-service method is slower than the direct-database solution, it not as significant as one might expect (for a grouped get, twice as slow).

Using the code

Intrinsic ASP

The use of built-in ASP sessions that are likely being used within your ASP applications will look something like the following:

Session("Sky") = "Blue";

On subsequent pages these values are read and the application has access to these values:

var skyString = Session("Sky");

New API Syntax

The following syntax would need to be used instead of the normal ASP session syntax, so that the JavaScript functions that encapulate the session bridge is used.

Setting One Key-Value Pair

In setting one key-value pair of session data, the syntax would be very similar to the current syntax of the built-in ASP sessions above. The following code would replace the current code that utilises intrinsic ASP sessions.

To set session data:

SetSessionValue("Sky", "Blue");

To get session data:

var SkyString = GetSessionValue("Sky");

This method would be recommended when relatively few key-value pairs (three or less) are set or retrieved on a single ASP.

Setting Multiple Key-Value Pairs

The cost of the above method is that for each setting or retrieving of a key-value pair, a round-trip to the web service is made. Given this can be a relatively costly operation in terms of response time, the following method is recommended on an ASP where a significant number (more than 3) key-value pairs are set or retrieved.

To set session data:

var sessionInfo = NewSession();
sessionInfo.Add(�Sky�, "Blue");
sessionInfo.Add(�Grass�, �Green�);
.
.
.
SetSession(sessionInfo);

To get session data:

var sessionInfo = GetSession();
var skyString = sessionInfo.Item(�Sky�);
var grassString = sessionInfo.Item(�Grass�);
.
.
.

Java Script Example

<%@ 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 Example

<%@ 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 Service Implementation

The web service consists of four simple methods, which supports getting / setting individual values within the ASP.NET session, and the slightly (but not much) more complex methods of getting / setting groups of session variables by the use of an XML payload.

public string getSessionValue(string sessionVariable)
public bool setSessionValue(string sessionVariable, string sessionValue)
public string getSessionValues()
public bool setSessionValues(string xmlSessionValues)

For the ASP.NET web service to support the creation and maintenance of sessions, then the following attribute is included in each of the methods. This then returns the ASP.NET_SessionId cookie into the responses, which can be used to bridge the session to the ASP code.

[WebMethod(EnableSession=true)]

That's pretty much it. You might want to include some more sophisticated implementation to integrate other server-side state information into the same interfaces. This version of the web service also has no authentication or other restriction on use, which given the open nature of a web service, might not be appropriate for your environment - therefore you might want to use a GUID or some other identification to show that a user is logged on as a parameter in each of the web service interfaces. Nice and simple.

ASP Bridge Implementation

The ASP side of the bridge is basically depdendent on the MSXML2.ServerXMLHTTP COM interface to perform calls to the web service server-side and the Scripting.Dictionary to provide a hash-table for maintaining a temporary (lifetime of page) copy of the session. Before the call is made to the web-service, it is important to ensure that if there is already an ASP.NET_SessionId cookie on the client workstation, it is passed as part of the server-side web service request. Likewise, that any cookies received from the web service are then included in the ASP response so that they are written to the client workstation for subsequent requests.

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;

The dictionary object is used to convert to and from a simple XML payload (basically just a collection of <SessionItem> nodes).

var dctSession = new ActiveXObject("Scripting.Dictionary");
var re = new RegExp("<SessionItem ", "g");

So, perhaps not the most elegant implementation, but it makes good use of what is available in ASP without resorting to rolling our own component. Again, nice and simple.

Deployment

A JavaScript file �ASPSessionWS.js� must be copied locally to where the ASP application is run. Include this script tag in any ASP file that utilises the ASP.NET sessions:

<script language="�Jscript�" runat="�server�" src=�\Script\ASPSessionWS.js� >
</script>

The web server only needs port 80 access available and the URL of where you have copied the web service updated in this script file (see below). The web service deployment is a simple matter of just copying your .asmx file to the web server that will be maintaining the session state, which in turn will need to change the web.config file to reflect wherever your database has been deployed (MSDN has tutorials for setting this up here).

function GetWebService(Function, Parameters)
{
    var xmlPayload = "";
    var sURL = "http://www.fullerdata.com/ASPBridge/bridge.asmx" + "/" + 
        Function;

Summary

Using a web service as a bridge from legacy ASP sessions to new ASP.NET sessions provides a pragmatic means of migrating your applications to new technologies, allowing the old and the new to share a single session context. The performance cost is significant, but might be a "good enough" solution as an interim for migration completely to .NET, especially within web-farm environments where the removal of web server affinity is a priority.

Links

There are already a number of other articles about using ASP.NET session state on CodeProject, of which the following are notable (IMHO):

There are some excellent articles on MSDN about ASP.NET sessions which are definitely worth reading:

History

  • March 2004 - Code Deployed to FullerData.com and Article Submitted to CodeProject.com

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here