|
|
Sessions Are ForeverSession information is stored in memory at the server until the session is either explicitly destroyed (Session.Abandon) or until the session times out (the user does not access any pages within a configurable amount of time). Suppose you would like to create sessions that are more permanent. Even though the original session might have timed out, it is possible to save much of the information and automatically restore it when the user returns. We'll look at how to do that, with and without relying on cookies. We'll store session data in a database with a simple schema: UserName and SessionData. The code in Listing 1 (global.asa) shows a Session_OnEnd handler. This routine is called every time a session is destroyed. It is your last chance to deal with data from the session. The code here opens a database connection and checks whether you are updating a previous session record or inserting a new one. In either case, it calls PackSession multiple times to put session data into a single block. It would be nice if we could iterate through the session variables and automatically pack them into the data block, but unfortunately, there is no collection method for the Session Object. So instead, you have to do it explicitly. For each session variable you want to save, call PackSession to add it to the data block. The user name is assumed to be in the session variable (Session("LoginName")). In September (Web Builder, September 1998, p. 63) we developed a simple logon scheme that does this. If your application uses a different login mechanism, such as NTLM, you can substitute a reference to the Request.ServerVariables("LOGON_USER") variable. Either way, the user name is used as a key to store the session information in a database. Listing 2 (packsession.inc) shows code for PackSession. This subroutine takes a session variable name as an argument and encodes the data in a way suitable for storing in a database. Notice that the code in this include file is in JScript (also called JavaScript). This is because we need the use of some functions that don't exist in VBScript. This is one of the nice things about ActiveServer Pages: You can mix and match scripting languages to take advantage of the strengths of each one. In this case, the escape function, which translates strings to a more Web-enabled form, is built into JScript and unavailable in VBScript. You could build it in VBScript, but that would require twenty or thirty lines of script. The call IsData checks whether the data can be represented as text. This is true if the data is a number, string, or Boolean. If the data is an object or a function it will be ignored. The data is encoded using the JScript escape function. This function takes most characters that are not letters or numbers and encodes them as their ASCII representation. For example, the string, "Look at '=', ';' and '%'." would be encoded as: "Look%20at%20%27%3D%27%2C%20%27%3B%27%20and%20%27%25%27%." We encode the data because characters like apostrophe cause trouble when stored literally in databases like Microsoft Access or SQL Server. In addition, we can now pack the data in the form <Server variable name>/<encoded data>; and rely on the "/" and ";" characters to unambiguously delimit the session string values. We choose not to use an "=" as the delimiter between the name and data for reasons that will be explained in the next section. This encoding makes it simple to code the other end. When a user logs on again you can execute the code in Listing 3 (loadsession.inc). The data block is fetched from the database and the JScript split function separates each session variable assignment into a separate element. Stepping through each element, the split function is called again to separate the session variable name from the data. The data is restored to its original form with a call to unescape and assigned to the appropriate session variable. This code can restore the session state for all variables that can be represented as text and stored in the database. If you need object instances such as database recordsets, the code to recover them can be provided at that point. Any database queries at that point could even be based on session data that you just restored. How You Gonna Keep 'Em Down on the Farm?In many installations, the Web sites are distributed across several physical servers, often called a server farm. Because session information is stored in physical memory by the ASP engine, it won't be available to all systems in a server farm. Suppose the first request for a page goes to Server One. During execution of the page it sets a session variable. A bit later a request comes in for a second page, but that gets routed to Server Two. It will not have access to the session data from the first page. One solution might be to use the code we just developed to read and write session information from a database at the beginning and end of each page. Although this would work, it would greatly affect the performance of the system. An alternate suggestion would be to use cookies to carry the information. There are limits on the use of cookies, such as a maximum of 20 per server and a maximum size of 4096 bytes. Since we are encoding all the session data into a single cookie, as long as the total amount of data per request stays small, this method will preserve session data across server boundaries. Listing 4 (sfarm.inc) contains subroutines for packing and unpacking session data into an HTTP cookie. The GetCookieSession subroutine uses the previously developed UnpackSession subroutine, passing it the data from the SessionData cookie. This call should go at the beginning of a page needing the session values. If necessary, you can also place code here to restore object-based session data (at a possible performance penalty). At the end of a page a call to SetCookieSession will pack up and save the session data. Notice that once again you need to explicitly call the PackSession subroutine for each session variable. When the Response object writes cookie data as it does in SetCookieSession, it is important that you know the rules when writing output. When information is written back to the browser by the Web server, it consists of a header (the HTTP header) followed by the data (the HTML). Cookie information is carried in the header, so you will get an error from ASP if you try to set a cookie after you have already written text. This includes calls to Response.Write as well as any HTML that exists outside the ASP <% %> delimiters. You can solve this problem in two ways. The first is to be careful in your coding and be sure that each ASP page using the sfarm.inc routines is organized with calls to GetCookieSession and SetCookieSession before any text output takes place. Alternately, you can set the Response.Buffer property to true. This tells the ASP engine to buffer all text until the ASP engine is completely done with the page. The downside of this method is that you won't see anything at the browser until the entire output is available. Listing 5 (testfarm.asp) shows a simple ASP page that uses this method. When the Cookie CrumblesFor some people and institutions, cookies are controversial. Ordinarily ASP uses a cookie to store a session ID. This is used as a key to the in memory database storing session data. Both of the methods we developed so far assume that cookies are enabled at the browser. If you want session-like capabilities without using cookies, add the packed data block to the request string of every URL. It's not pretty, but it can be done. The code in Listing 6 (nocookies.inc) has a subroutine named SetResponseSession that should be called at the end of each page. It generates a bit of JavaScript into the file that contains the current session data-block. This code will be executed at the client. Each HREF to a URL in the same site needs to use a call to SessionHREF. This subroutine adds the session data to the request. The session data is passed from page to page as a request variable named SessionData. The GetRequestSession subroutine should be called at the top of each page to unpack and set up session data appropriately. Here's a simple page that passes session information along with the request: <%Response.Buffer = trueGetCookieSession%><!- #include file="sfarm.inc" -><!- #include file="loadsession.inc"- ><HTML><BODY>ONE = <%=Session("one")%> <BR><% Session("one") = Session("one") + 1 %></BODY> </HTML> <% SetCookieSession %>
Think you're up to it Kid?That last method might end up putting large amounts of data into the URL. A better method would be to pass the information as POST data in a hidden field. This allows more data to be passed and doesn't add all the extra characters to the URL. To do this, you must do two things. First, create an include file that creates a <FORM> with a hidden element in it. For example: <FORM name="SessionData" method="POST"> <INPUT name="HiddenData" type="hidden"> </FORM> This file should be included somewhere inside the <BODY> tags in each ASP page. Second, change the SessionHREF routine, to emit JavaScript code that submits the URL correctly: SessionData.action=url + "?" + qs SessionData.HiddenData.value=sData SessionData.submit() The rest is left as an exercise for the reader. So, despite limits on the type and amount of data being passed, it is possible to get sessions under adverse conditions. ASP has a very rich set of capabilities. When the simple methods are unavailable, look a little deeper. You can usually build an equivalent out of the tools ASP gives you. What's in a Name?As a last note, let's clear up some confusion about JavaScript, JScript, and ECMAScript. JavaScript is the term originally used by Netscape for the client-side scripting language they introduced in the 2.0 version of their browser. JScript was Microsoft's competing but slightly different scripting language introduced in IE 3.0. Neither language is really based on Java, but is "Java-like" in its syntax. Amazingly, all the industry players got together under the auspices of the standards organization known as the ECMA (European Computer Manufacturers Association) and hammered out a standard for a common scripting language, called ECMAScript. The ECMAScript-262 specification is available at www.ecma.ch/stand/ecma-262.htm. The current release of the JScript engine conforms to this standard. When specifying the language on an ASP page, such as <%@ language=JScript %>, either JScript or JavaScript can be used interchangeably. Visual Basic programmers find that VBScript is a natural extension to their skill-set and the scripting language of choice. Java, C, or C++ programmers find that JScript is very "C-like" (or "Java-like") in its syntax. As we saw in the article above, there are capabilities built into either language that are unavailable in the other. Knowing both languages is a good idea, and ASP allows you to easily mix the languages throughout a page using <SCRIPT> blocks. The next releases of scripting engines from
Microsoft (5.0) add capabilities to both languages that make them much more
comparable. With these releases the choice of VBScript vs. JScript becomes much
more one of style. Oh, and to complicate matters there are script engines
available for Perl, REXX, Python, and many others. |
|
|
|
|
|
| |
Host Department NOLIMIT Web Hosting 0800 Numbers halloween mask Diesel sunglasses NJ Pool Contractor answering service fax server swimming pool contractor Teleconference MSN sunglasses |
Email TopXML
|
|
Front Page Daily Stuff TopXML Forum XML blogs XML Newsgroups BizTalk Biztalk Utilities Biztalk Utilities Tutorial B2B SAP XML Microsoft .NET Dotnet System XML Soapformatter SQLXML XMLserializer XQuery PHP PHP SimpleXML PHP XML Dom PHP XML RPC PHP XSLT Java Java Java XML Xalan Microsoft ASP ASP Schemas XML SQL Server XML XMLDom XSL XSL Tutorial XSLT Stylesheets General Javascript CSS XHTML WAP |