Active User Count Without Global.asaby Josh Painter( Webmaster of Toastforums.com) Introduction Introduction
So you've got your killer website up and running, and you're wanting to add a few little "perks." One of the hottest trends today is to show an "Active User Count" that shows exactly how many people are currently connected to your website. Many articles have already been written showing exactly how to do this using the global.asa file, so I won't even bother to explain that method. ASP 101 has a great article explaining the global.asa method of counting active users.What I'd like to do is show you how to not use the global.asa file. I'm not saying using the global.asa file is bad--far from it. If you can use it then please do; it will probably yield a bit better performance. But there are many reasons why you might not want (or simply can't) use a global.asa file. Perhaps your host does not allow a global.asa. Maybe your site is hosted in a subdirectory of an existing site, and they won't set up an IIS application for you, so a global.asa file will do you no good. Or you might even not want to mess with an existing global.asa file, or not have access to do so. Personally, I needed to have this functionality for a web application I've been building (shameless link) and one of my design goals was that the Active User Count would NOT require use of a global.asa. I didn't want to bother with helping webmasters try to merge my code in with an existing global.asa, or guide them through setting up an existing IIS application so they could use my global.asa. Many of them couldn't even if they know how, because their web host doesn't allow it. So, this is the solution. Quick Explanation
To make a manual Active User Count, we have a few options about where to store the active users on the server. We could store them in a database, in a text file, or in server memory in an Application variable. I chose to go with Application variables. Databases may be fast, but I don't like to query a database on *every* hit to a page unless absolutely necessary. Text files could get cumbersome, and I don't want to worry about file permissions. So the logical choice is Application variables. Application variables are very fast to access, since they reside in the web server's memory, and are available on just about every ASP web host out there. I make use of three Application variables: one that holds the number of online users, another that holds a list of unique users and the last time of their activity, and the final variable remembers when the last cleanup occurred. We'll use the SessionID for a unique key of each user, and the simple Now() function to tag each SessionID with the time of last activity. So, without any more explaining, here is the "LogActiveUser" function: LogActiveUser Routine Sub LogActiveUser Dim strActiveUserList Dim intUserStart, intUserEnd Dim strUser Dim strDate
strActiveUserList = Application("ActiveUserList")
If Instr(1, strActiveUserList, Session.SessionID) > 0 Then Application.Lock intUserStart = Instr(1, strActiveUserList, Session.SessionID) intUserEnd = Instr(intUserStart, strActiveUserList, "|") strUser = Mid(strActiveUserList, intUserStart, intUserEnd - intUserStart) strActiveUserList = Replace(strActiveUserList, strUser, Session.SessionID & ":" & Now()) Application("ActiveUserList") = strActiveUserList Application.UnLock Else Application.Lock Application("ActiveUsers") = CInt(Application("ActiveUsers")) + 1 Application("ActiveUserList") = Application("ActiveUserList") & Session.SessionID & ":" & Now() & "|" Application.UnLock End If End Sub
|
So let's take this line by line. First, we are copying the Active User list into a local variable. We are going to be doing lots of string manipulation, and we don't want to make a call out to the Application Variables collection every time we need to inspect the Active User list. Then we need to check to see if this user is already in the list. We do this by the simple Instr call to see if his SessionID exists. If it doesn't, its easy--we just add one to the ActiveUsers parameter and add this new SessionID and current time to the Active User list. If the SessionID already exists, we've got a bit more work to do. We've got to find this user in the list and update his time stamp. The ActiveUserList variable will look something like this at any one time:
| 716763555:1/4/2001 11:10:23 PM|616733525:1/4/2001 11:11:45 PM|8616433235:1/4/2001 11:15:58 PM | So we need to extract the user that we're looking for, change his timestamp to Now(), and insert him back in the list. Pretty easy to do. First we find the beginning of the user by searching for SessionID. Since the users are delimited by a pipe "|" symbol, we just search for the pipe starting with the beginning of the SessionID to find the end of the User's timestamp. Now that we have the beginning and the end, we can just replace this entire "chunk" of the string with the SessionID and current timestamp. This will effectively "reset" the user's timestamp. But, how do we clean up ActiveUsers as their timestamps get old? Let's look at the ActiveUserCleanup routine. ActiveUserCleanup Routine
Sub ActiveUserCleanup Dim ix Dim intUsers Dim strActiveUserList Dim aActiveUsers Dim intActiveUserCleanupTime Dim intActiveUserTimeout
intActiveUserCleanupTime = 1 'In minutes, how often should the ActiveUserList be cleaned up. intActiveUserTimeout = 20 'In minutes, how long before a User is considered Inactive and is deleted from ActiveUserList
If Application("ActiveUserList") = "" Then Exit Sub
If DateDiff("n", Application("ActiveUsersLastCleanup"), Now()) > intActiveUserCleanupTime Then
Application.Lock Application("ActiveUsersLastCleanup") = Now() Application.Unlock
intUsers = 0 strActiveUserList = Application("ActiveUserList") strActiveUserList = Left(strActiveUserList, Len(strActiveUserList) - 1)
aActiveUsers = Split(strActiveUserList, "|")
For ix = 0 To UBound(aActiveUsers) If DateDiff("n", Mid(aActiveUsers(ix), Instr(1, aActiveUsers(ix), ":") + 1, Len(aActiveUsers(ix))), Now()) > intActiveUserTimeout Then aActiveUsers(ix) = "XXXX" Else intUsers = intUsers + 1 End If Next
strActiveUserList = Join(aActiveUsers, "|") & "|" strActiveUserList = Replace(strActiveUserList, "XXXX|", "")
Application.Lock Application("ActiveUserList") = strActiveUserList Application("ActiveUsers") = intUsers Application.UnLock
End If
End Sub |
Let's look at this routine line by line. The first thing we do is set some internal variables that decide when to cleanup, and how long before a User is considered Inactive. The variables intActiveUserCleanupTime and intActiveUserTimeout control these times, respectively. If the ActiveUserList is blank, we have nothing to do here, so Exit Sub. If the difference (in minutes) between the time we last ran the cleanup procedure and the time right now is greater than intActiveUserCleanupTime, let's run cleanup (this is better for performance--we only want to run cleanup every minute or so, not every time the calling script is hit). Immediately set the ActiveUsersLastCleanup variable to Now, so if another script calls this procedure while we are doing our work it will think that it is not yet time to run cleanup. Now we will copy the ActiveUserList to a local variable for increased performance and convert it to an array so we can loop through all the users. We loop through each user, and if we find a timestamp that is older than the intActiveUserTimeout variable, we will replace the entire User with "XXXX", and delete him later (we must do this because VBScript does not natively support any advanced array handling like deleting or inserting elements). Now that we've marked inactive users, we'll convert the Array back to a string. We end the string with our delimiter "|" to make the next step easier. Replace any occurences of "XXXX|" that we find to "", effectively deleting the user from the ActiveUserList. Now its time to store the variables back into the Application variables. Getting it up and running with your Site This should be relatively easy. Just put these functions in a file and include it with any pages that will need to log Active Users and show an Activer User Count. So your script might look something like this:
<%
Call LogActiveUser() Call ActiveUserCleanup()
Response.Write "There are " & Application("ActiveUsers") & " active users currently online."
%>
|
Shameless Plug If you would like to see this code in action, head over to toastforums.com. See the "Current Online Forum Users" up in the right corner? That is using this exact code! Oh, and if you need a free ASP message board for your website, try Toast! Happy coding! Josh Painter | DISCLAIMER: The content provided in this article is not warranted or guaranteed by Developer Shed, Inc. The content provided is intended for entertainment and/or educational purposes in order to introduce to the reader key ideas, concepts, and/or product reviews. As such it is incumbent upon the reader to employ real-world tactics for security and implementation of best practices. We are not liable for any negative consequences that may result from implementing any information covered in our articles or tutorials. If this is a hardware review, it is not recommended to open and/or modify your hardware. |
More ASP Code Articles More By aspfree developerWorks - FREE Tools! | Hold your calendar on January 30, 2008 for this free webcast on the new i5/OS. Rational's Enterprise Modernization products will be discussed at this webcast as they help to drive the application development environment for this new System i OS. <br />And learn how i5/OS will take you to the next step of efficient, resilient business processing. You will hear about the new i5/OS capabilities as it will be the most significant i5/OS release in years. If you cannot join the webcast on 1/30/08 you can still use this link to listen to the replay.<br /> FREE! Go There Now!
| | | | Join this Rational Talks to You teleconference, featuring Paul Boustany and Mark Krasovich, to speak to the experts about becoming a Rational ClearCase power user. Get a chance to ask your questions and learn tips and tricks for using Rational ClearCase in Agile development FREE! Go There Now!
| | | | Effective governance for lean development isn’t about command and control. Instead, the focus is on enabling the right behaviors and practices through collaborative and supportive techniques. Hear from Scott Ambler on how it is far more effective to motivate people to do the right thing than it is to force them to do so. Learn how to form a lightweight, collaboration-based framework that reflects the realities of modern IT organizations. FREE! Go There Now!
| | | | Visit IBM developerWorks to download a free trial of the latest release of IBM Lotus Sametime Standard V8.0. Lotus Sametime Standard V8.0 is a platform for unified communications and collaboration that combines security features with an extensible, open solution including integrated Voice over IP, geographic location awareness, mobile clients, and a robust Business Partner community offering telephony and video integration. FREE! Go There Now!
| | | | As systems increase in complexity, communication between systems and software teams becomes more and more difficult. Now, there’s a way to improve product quality and communication.<br />Read the “Model Driven Systems Development” white paper to see how. Also included in this kit are more educational white papers, customer examples, tutorials, informative Webcasts, and best practices for designing, building and managing systems.<br /> FREE! Go There Now!
| | | | Learn how to implement a build management system that uses and extends your existing automation technologies. This tutorial shows, step-by-step, how to install and configure IBM Rational Build Forge to manage builds for Jakarta Tomcat from source code. FREE! Go There Now!
| | | | Ken Krugler, co-founder of code search company Krugle, and Laura Merling, vice president of Marketing and Business Development for Krugle, join to talk about the ins and outs of code search and what it means as a new feature for developerWorks users. FREE! Go There Now!
| | | | This paper is about the critical role that a discipline called integrated requirements management can play in helping to ensure that your business goals and IT investments are continuously aligned—whether you are sourcing, integrating, building or maintaining software. It also looks at ways that automated IBM Rational® products can work together to help you use requirements in the very best way. FREE! Go There Now!
| | | | Visit IBM developerWorks to try the IBM SOA Sandbox for connectivity. The SOA Sandbox for connectivity provides a trial environment with the tooling and components to help you explore how to effectively connect your infrastructure and integrate all of the people, processes and information in your company. Use the hosted sandbox to explore SOA techniques that streamline connecting existing IT assets together, as well as learn how to connect them to new business logic. FREE! Go There Now!
| | | | The unprecedented scope of a service-oriented architecture (SOA) initiative brings to the forefront a number of management and governance issues that were sidestepped in the past. The key to a successful SOA implementation is managing and governing activities throughout the entire SOA delivery lifecycle by ensuring that services conform to the needs of all of the business’s stakeholders. Learn how service lifecycle management allows the business to ensure that the process by which services are defined, created, tested, deployed, optimized and retired is manageable, repeatable and auditable. FREE! Go There Now!
| | | | All FREE IBM® developerWorks Tools! | |