问题
I want to know the number of visitors online on my site. I did my research and found two solutions.
Source: Code Project
Online active users counter in ASP.NET
It is easy to setup and easy to use but it increases the user count for every Ajax request/response too. My home page alone has 12 Ajax requests(8 requests to one page and 4 requests to another page). This dramatically increases the user count.
Source: Stack Overflow Q/A
Count the no of Visitors
This one works exactly the same as the previous one.
Source: ASP.Net Forum How to see "who is online" using C#
This one looks better than the previous two. Here is the detail code of this solution.
void Application_Start(object sender, EventArgs e)
{
// Code that runs on application startup
HttpContext.Current.Application["visitors_online"] = 0;
}
void Session_Start(object sender, EventArgs e)
{
Session.Timeout = 20; //'20 minute timeout
HttpContext.Current.Application.Lock();
Application["visitors_online"] = Convert.ToInt64(HttpContext.Current.Application["visitors_online"]) + 1;
HttpContext.Current.Application.UnLock();
}
void Session_End(object sender, EventArgs e)
{
HttpContext.Current.Application.Lock();
Application["visitors_online"] = Convert.ToInt64(HttpContext.Current.Application["visitors_online"]) - 1;
HttpContext.Current.Application.UnLock();
}
It seems to be able to ignore the increasing the count for every Ajax response but it still adds up for each page refresh or page request.
Is there any approach to count the accurate number of online visitors in ASP.Net?
回答1:
You can never get an entirely accurate number: there is no way to (reliably) detect that a user "has navigated to another site" (and left yours) or that that user "closed the browser".
The Session_Start/Session_End way has the problem that Session_End is only called for "InProc" sessions, not if the sessions are stored in StateServer or SqlServer.
What you might be able to do:
- Hold a
Dictionary<string, DateTime>
in Application scope. This stored session-id's (the string key) against the time of latest access (the DateTime value) - For each request with a valid session, find the session entry in the dictionary and update it's latest-access time (add a new entry if not found)
- When you want to get the number of online users, first loop through all entries in the dictionary and remove items where the session timeout has passed. The remaining count is the number of online users.
One problem (at least): if one user uses two browsers simultaneously, he has two sessions open and is counted double. If users always log in, maybe you could count on login-id instead of session-id.
回答2:
I want to propose something completely another: try to use Google Analytic for this. These guys add beta functionality that allows tracking online statistics now.
EDIT: You don't get me. I mentioned not standard Google Analytic functionality. I mentioned new feature - Real-Time. Check next article for details - What’s happening on your site right now? or watch this video - Google Analytics real-time beta
回答3:
Just as Hans mentioned, you will probably have to switch your session state to StateServer
or SQLServer
, but this is not something a snippet of code can do. There is a very good reliable and detailed article on codeproject that treats this problem properly.
回答4:
This is the source code I implemented according to Hans Kesting's suggestion.
Global.asax
void Session_Start(object sender, EventArgs e)
{
System.Collections.Generic.Dictionary<string, DateTime> Visitors =
new System.Collections.Generic.Dictionary<string, DateTime>();
Visitors.Add(Session.SessionID, DateTime.Now);
HttpContext.Current.Application.Lock();
Application["Visitors"] = Visitors;
HttpContext.Current.Application.UnLock();
}
HttpHandleder.cs
private static void UpdateVisitors()
{
System.Collections.Generic.Dictionary<string, DateTime> Visitors = (System.Collections.Generic.Dictionary<string, DateTime>)HttpContext.Current.Application["Visitors"];
Visitors[HttpContext.Current.Session.SessionID] = DateTime.Now;
}
AnyPage.aspx.cs(where you want to get the number of total online users)
protected int GetCurrentOnlineUsers()
{
int total = 0;
Dictionary<string, DateTime> Visitors = (Dictionary<string, DateTime>)Application["Visitors"];
foreach (KeyValuePair<string, DateTime> pair in Visitors)
{
TimeSpan Remaining = DateTime.Now - pair.Value;
int remainingMinutes = Convert.ToInt32(Remaining.TotalMinutes);
if (remainingMinutes < 21) //Only count the visitors who have been active less than 20 minutes ago.
total++;
}
return total;
}
回答5:
Hans's solution is really great and working exactly what I want but I just found this article on MSDN recently which seems to be the best practice for this purpose.
REF: http://msdn.microsoft.com/en-AU/library/system.web.httprequest.anonymousid.aspx
Global.asax
void Application_Start(Object sender, EventArgs e)
{
// Initialize user count property
Application["UserCount"] = 0;
}
public void AnonymousIdentification_Creating(Object sender, AnonymousIdentificationEventArgs e)
{
// Change the anonymous id
e.AnonymousID = "mysite.com_Anonymous_User_" + DateTime.Now.Ticks;
// Increment count of unique anonymous users
Application["UserCount"] = Int32.Parse(Application["UserCount"].ToString()) + 1;
}
.ASPX file
<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
void Page_Load(object sender, EventArgs e)
{
if (Application["UserCount"] != null)
{
lblUserCount.Text = Application["UserCount"].ToString();
lblCurrentUser.Text = Request.AnonymousID;
}
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>AnonymousID Example</title>
</head>
<body>
<form id="form1" runat="server">
<div>
Number of users:
<asp:Label ID="lblUserCount" Runat="server"></asp:Label><br />
Current user:
<asp:Label ID="lblCurrentUser" Runat="server"></asp:Label><br />
</div>
</form>
</body>
</html>
回答6:
Why not check the user IP to get unique visits. Add them to a hashset so you can do nice things like make a heatmap using a location API:
// count users online on all desktopsites
void Session_Start(object sender, EventArgs e)
{
try
{
// lock application object
Application.Lock();
// get hashset containing all online ip adresses
var ips = (HashSet<string>)Application["visitors_online_list_ip"];
// get user ip
var ip = HttpContext.Current.Request.UserHostAddress;
// add ip to hashset
ips.Add(ip);
// store ip in session to delete when session ends
Session["ip"] = ip;
// save hashset
Application["visitors_online_list_ip"] = ips;
// unlock application object
Application.UnLock();
}
catch {}
}
void Session_End(object sender, EventArgs e)
{
try
{
// lock application object
Application.Lock();
// get hashset containing all online ip adresses
var ips = (HashSet<string>)Application["visitors_online_list_ip"];
// get user ip from Session because httpcontext doesn't exist
var ip = Session["ip"].ToString(); ;
// remove ip from hashset
ips.Remove(ip);
// save hashset
Application["visitors_online_list_ip"] = ips;
// unlock application object
Application.UnLock();
}
catch {}
}
来源:https://stackoverflow.com/questions/11389880/how-to-get-the-accurate-total-visitors-count-in-asp-net