Naive ASP.NET Session Count Wrong - c#

I use the following code to count the number of currently open sessions in my ASP.NET (2.0/3.5) application (ASMX web service, legacy code), but if it runs long enough the count stops matching the built in performance counters (my count is higher, Session_End seems to not be invoked sometimes). The sessions are InProc. What might I be missing?
public class Global : System.Web.HttpApplication
{
protected void Application_Start(object sender, EventArgs e)
{
Application["OpenSessionCount"] = 0;
}
protected void Session_Start(Object sender, EventArgs e)
{
Application.Lock();
Application["OpenSessionCount"] = (int)Application["OpenSessionCount"] + 1;
Application.UnLock();
/* Set other Session["foo"] = bar data */
}
protected void Session_End(Object sender, EventArgs e)
{
Application.Lock();
Application["OpenSessionCount"] = (int)Application["OpenSessionCount"] - 1;
Application.UnLock();
}
}
"Just use performance counters!"
Yes, I'm just asking because I'm curious where I went wrong.

The Session_End is invoked in two situations:
When Session.Abandon() is called
Immediately after the Session expires
If you close the browser, the Seesion_End event fire when Session Expires.
See MSDN lib

Sessions do not actually begin unless you store something in the Session dictionary. So, you won't get a Session_End event for any that don't actually have a session object allocated.
From MSDN:
When using cookie-based session state, ASP.NET does not allocate storage for session data until the Session object is used. As a result, a new session ID is generated for each page request until the session object is accessed. If your application requires a static session ID for the entire session, you can either implement the Session_Start method in the application's Global.asax file and store data in the Session object to fix the session ID, or you can use code in another part of your application to explicitly store data in the Session object.
public class Global : System.Web.HttpApplication
{
protected void Application_Start(object sender, EventArgs e)
{
Application["OpenSessionCount"] = 0;
}
protected void Session_Start(Object sender, EventArgs e)
{
Application.Lock();
// Store something every time to ensure the Session object is allocated.
HttpContext.Current.Session["dummy"] = "Foo";
Application["OpenSessionCount"] = (int)Application["OpenSessionCount"] + 1;
Application.UnLock();
/* Set other Session["foo"] = bar data */
}
protected void Session_End(Object sender, EventArgs e)
{
Application.Lock();
Application["OpenSessionCount"] = (int)Application["OpenSessionCount"] - 1;
Application.UnLock();
}
}
Reference: ASP.NET: Session.SessionID changes between requests

Related

ASP.NET get count of logged-In User

I would like to display number logged-In users count in my page. I implemented this using Application Variable, but the problem is its not decreasing the count when user close the browser.
First i opened the web application using IE the count became 1, then i opened the app using firefox the count became 2. When i close any one of the browser the count not getting decrease.
void Application_Start(object sender, EventArgs e)
{
Application["UsersCount"] = 0;
}
void Application_End(object sender, EventArgs e)
{
}
void Session_Start(object sender, EventArgs e)
{
if (Application["UsersCount"] != null)
{
Application.Lock();
Application["UsersCount"] = ((int)Application["UsersCount"]) + 1;
Application.UnLock();
}
}
void Session_End(object sender, EventArgs e)
{
Application.Lock();
Application["UsersCount"] = ((int)Application["UsersCount"]) - 1;
Application.UnLock();
}
Any other way to achieve this?
Thank you.!
This is not so simple to implement. To be logged in doesn`t actually necessary mean that user doing something. You should set some timeout (probably the same as auth cookie life-time) and check the last activity mark of each user. Special DB table is good for that, but if you want quick and dirty solution:
You can keep IDictionary<Guid, DateTime> which you will update on each request. Guid is for UserID, DateTime for the last activity. On each request (probably somewhere in MasterPage code behind) you update this dictionary with current DateTime. Then you can check count of IDs with DateTime less than timeout.
IDictionary<Guid, DateTime> userActivityLog = Application["UserActivityLog"] as IDictionary<Guid, DateTime>;
DateTime timeout = DateTime.Now.AddHours(-1); // one hour timeout
int loggedCount = userActivityLog.Count(x => x.Value > timeout);

how to avoid re initialization of session value after redirecting to same page

I have intialized some session variables in page load method to zero. Then I am modifying them in button press method. I am using one session variable as a counter but when I am redirecting the page to the same page, the variables are intialized again. Please help me to prevent this re-initialization. I don't want to use static variables.
The scenario is-
protected void Page_Load(object sender, EventArgs e)
{
session["counter"] = 0;
}
protected void Button1_Click(object sender, EventArgs e)
{
int count = (int)session["counter"];
count++;
session["counter"] = count;
response.redirect("same page");
}
Assuming you just want to check for a non set session variable and if so, set it to zero, then you could just do:
protected void Page_Load(object sender, EventArgs e)
{
if(session["counter"] == null) {
session["counter"] = 0;
}
}
There are also a range of client side options you could use, depending on the situation.
Use
protected void Page_Load(object sender, EventArgs e)
{
if(!IsPostBack)
session["counter"]=0;
}
protected void Button1_Click(object sender, EventArgs e)
{
int count=(int)session["counter"];
count++;
session["counter"]=count;
//remove response.redirect("same page");
}
Your buuton is server side so your page will postback so you do not need to use response.redirect("same page");
If you are indeed redirecting, and not posting back, just check, on page load, if your initial variable has been set? If not, set it. If it is set, ignore setting it.
'set initial value
if session("counter") is nothing then
session("counter") = 0
end if
If you are posting back, you could also use the above, or you could:
If not isPostBack then
session("counter") = 0
end if
You can move that initialisation to a different page. Instead of directly jumping to your "same page" from another part of your application, julp to an "initializer" instead. That page initializes your session variables and immediately redirects to your "same page".
Your "Button_Click" still redirects to "same page", bypassing that initialisation.

ASP.Net C# Variables not storing on web page

So i have the code..
int var1 = 0;
protected void cmdvar1_Click(object sender, EventArgs e)
{
var1= var1+ 10;
lblvar1.Text = var1.ToString();
}
And when clicking this, its great.. it takes the int, adds 10 to it, then displays it.. however it won't display any more than 10, did some playing around and came to the conclusion, that its not because the label isnt updating, it just simply isnt adding 10 to the previous 10 on the variable. What am i doing wrong? What am I mising? Do i need to store the variable info in a cookie or something?
This is due to the lifecycle of ASP.NET. Storing private fields behind the web page isn't the same as how it works with WinForms. If you want to persist information across post backs you need to store it in some persistent storage i.e. Session/ViewState/Database etc.
private int var1 = 0;
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
// load var1 from cache
Int32.TryParse((Session["var1"] ?? 0).ToString(), out var1);
}
}
protected void cmdvar1_Click(object sender, EventArgs e)
{
var1 += 10;
Session["var1"] = var1; // cache var1
lblvar1.Text = var1.ToString();
}
So I would strongly suggest looking into a different platform. Perhaps ASP.NET MVC... However you can use something like the following to get arround your problem.
private int MyNum
{
get{ return (int)ViewState["MyNum"] ?? 0; }
set { ViewState["MyNum"] = value; }
}
Then just use MyNum as your integer your incrementing.
Assuming that lblvar1 is a Label control then you can do the following. The reason this will work is because .NET automatically take care of the state of UIControl
protected void cmdvar1_Click(object sender, EventArgs e)
{
var var1 = Convert.ToInt32(lblvar1.Text);
var1= var1+ 10;
lblvar1.Text = var1.ToString();
}
As suggested in the comments, you have to wrap your universe around statelessness before you will get to producing meaningful web applications.
The ASP.NET equivalent to accomplish state-like behavior is to use the Session collection which is available to every web page.
protected void cmdvar1_Click(object sender, EventArgs e)
{
int var1 = (int)Session["yourInteger"];
var1 += 10;
Session["yourInteger"] = var1;
lblvar1.Text = var1.ToString();
}
You are obviously setting an initial value for Session["yourInteger"] somewhere else, just one time.
The problem with Session is that it makes your application potentially buggy and somewhat unscalable. The more you use it, the worse on both accounts.
Use Session body, HTTP is a stateless Protocol, once you postback you loose the current variable value,
Solution:
int var1=0;
protected void cmdvar1_Click(object sender, EventArgs e)
{
if(Session["var1"]!=null)
var1=int.Parse(Session["var1"].ToString());
else
var1=0;
var1= var1+ 10;
lblvar1.Text = var1.ToString();
Session["var1"]=var1;
}

Sharing data between users - without a database table

I have an ASP.NET (4.0) webforms application and I would like to know what options I have when it comes to sharing data between users in my web application.
The most obvious solution would be a database table. But are there any alternatives? I've read something about "Application scope", but I'm not sure that it'll be useful for this scenario.
Applications is what you are searching for.
if (Application["CurrentUsers"] == null)
Application["CurrentUsers"] = 0;
Application["CurrentUsers"] += 1;
Just an example for an current online counter.
To react to the lifetime, see the global.asax:
protected void Application_Start(object sender, EventArgs e)
{
Application["CurrentUsers"] = 0;
}
protected void Application_End(object sender, EventArgs e)
{
Application["CurrentUsers"] = null;
}
Application object Or store it in a in-memory database

asp.net visitors count (online users) for today-yesterday in .net 4

i wrote the below codes for visitors count (online users) for my application :
reference :
http://aspdotnetfaq.com/Faq/How-to-show-number-of-online-users-visitors-for-ASP-NET-website.aspx
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.SessionState;
using CardCharge.Classes;
namespace CardCharge
{
public class Global : System.Web.HttpApplication
{
protected void Application_Start(object sender, EventArgs e)
{
Application["OnlineUsers"] = 0;
}
protected void Session_Start(object sender, EventArgs e)
{
Application.Lock();
Application["OnlineUsers"] = (int)Application["OnlineUsers"] + 1;
Application.UnLock();
}
protected void Application_BeginRequest(object sender, EventArgs e)
{
}
protected void Application_AuthenticateRequest(object sender, EventArgs e)
{
}
protected void Application_Error(object sender, EventArgs e)
{
}
protected void Session_End(object sender, EventArgs e)
{
Application.Lock();
Application["OnlineUsers"] = (int)Application["OnlineUsers"] - 1;
Application.UnLock();
}
protected void Application_End(object sender, EventArgs e)
{
}
}
}
also i found the below link that uses IHttpModule :
http://blog.sb2.fr/post/2008/12/01/HowTo-Get-Current-Online-Users-Count-and-Infos-with-ASPNET.aspx
i prefer to use simple global.asax for my purpose , but these two ways are too old (3 years earlier)
is there any better way in .net 4 for getting online users(visitors count) out there?
also for getting some counts (such as yesterday) i need database !
but is it ok to connect sql server 2008 in session_start or specially session_end in global asax ?
thanks in advance
The "standard" approach I have seen is to use the Session_Start and Session_End within global.asax. ASP.net 4 has not changed this functionality. The only real limitation to this approach is that the server will still believe that the user is logged on until the session ends, which does not happen until the number of minutes has passed as specified in the session timeout configuration.
See this page for more information about session timeout:
http://forums.asp.net/t/1283350.aspx
One more robust, and newer, but much more difficult approach, is to use polling to ensure that the client is always connected to the server. See this Wikipedia article for an overview of the subject:
http://en.wikipedia.org/wiki/Comet_(programming))

Categories

Resources