asp.net 在线人数统计
对于做B/S开发的人来说,统计在线的人数是个很重要的工作,一般的统计方法是利用Application保存在线人数。我今天要讲的也是用这个方法,但是,在这个方法上增加一点内容,就是,当用户直接关闭IE后,也要立刻将在线人数减少,而一般的方法是要等待Session过期后才能统计。好了,开始了。 1、首先,配置web.config 将Session的状态配置成如下,为什么我就不说了。 <sessionState mode="InProc"></sessionState> 2、Global.asax的各个方法 <%@ Application Language="C#" %> <script runat="server"> void Application_Start(object sender, EventArgs e) { // 在应用程序启动时运行的代码 Application.Add("OAS_Line_Counts", 0); } void Application_End(object sender, EventArgs e) { // 在应用程序关闭时运行的代码 Application.RemoveAll(); } void Application_Error(object sender, EventArgs e) { // 在出现未处理的错误时运行的代码 } void Session_Start(object sender, EventArgs e) { // 在新会话启动时运行的代码 Session.Timeout = 30; } void Session_End(object sender, EventArgs e) { // 在会话结束时运行的代码。 // 注意: 只有在 Web.config 文件中的 sessionstate 模式设置为 // InProc 时,才会引发 Session_End 事件。如果会话模式设置为 StateServer // 或 SQLServer,则不会引发该事件。 Application.Lock(); if (Application["OAS_Line_Counts"] != null) { Application["OAS_Line_Counts"] = Int32.Parse(Application["OAS_Line_Counts"].ToString()) - 1; if (Int32.Parse(Application["OAS_Line_Counts"].ToString()) < 0) Application["OAS_Line_Counts"] = 0; } Application.UnLock(); } </script> 3、登陆成功后的人数加一 Application.Lock(); if (Application["OAS_Line_Counts"] != null) { Application["OAS_Line_Counts"] = Int32.Parse(Application["OAS_Line_Counts"].ToString()) + 1; } else { Application["OAS_Line_Counts"] = 1; } Application.UnLock(); 4、退出时减一 Session.RemoveAll(); Session.Abandon();//取消会话状态就会触发Session_End的事件 5、当关闭窗口时的统计(关键的地方) 如果页面是用框架结构做的,则里面不能用.net的控件,而且没有body,因此,我们只能调用其他的页面来实现。 我的方法如下: <script language="javascript" type="text/javascript"> function PageClose() { //这样写,主要是防止刷新也触发该事件 if(event.clientX>document.body.clientWidth-30 && event.clientY<0 || event.altKey) //event.altKey表示按下了Alt按纽 { //alert("X:"+event.clientX+" Y:"+event.clientY+" "+document.body.clientWidth); window.location .href="PageCloseCount.aspx"; widnow.close(); } } </script> </head> <frameset onbeforeunload="PageClose()" rows="88,*" cols="*" framespacing="0" frameborder="no" border="0" bordercolor="#0099FF"> <frame src="top.aspx" name="topFrame" scrolling="NO" noresize> <frameset rows="*" cols="148,*" framespacing="0" frameborder="no" border="0" bordercolor="#33CCFF"> <frame src="left.aspx" name="leftFrame" scrolling="yes" noresize> <frame src="desktop.aspx" name="mainFrame" scrolling="yes"> </frameset> </frameset> <noframes><body> </body></noframes> PageCloseCount里调用的方法 public void PageClose() { System.Web.HttpContext.Current.Session.RemoveAll(); System.Web.HttpContext.Current.Session.Abandon(); } 如果不是用框架做的就要简单些了,可以不需要调用其他的页面来执行方法,用他自己就可以了。 部分代码: <script language="javascript" type="text/javascript"> function PageClose() { if(event.clientX>document.body.clientWidth-30 && event.clientY<0 || event.altKey) //event.altKey表示按下了Alt按纽 { document.all('ButtonPageClose').click(); document.all('ButtonPageClose').focus(); } } </script> </head> <body onbeforeunload="PageClose()"> 按纽里的方法同上面一样,也是取消会话。 这个方法我测试了,好象基本上可以,但是又好象有时没调用到,好象是和用户点击按纽的位置有关。 统计在线用户列表asp.net 以下有改动: .NET对用户的状态控制采用SESSION(COOKIE也可以,但是无法在服务器端触发SESSIONEND事件,所以这里说到的方法是基于使用SESSION的) .NET和 ASP中都可以使用Global.asax来对SESSIONEND事件进行程序设置,网上有很多关于使用global.asax结合APPLICATION和SESSIONEND事件 写的统计在线人数的方法,但是我没找到统计详细的在线用户信息的资料。 因此,我自己用了一个方案来实现,并调试成功。 思路:通过Session_End事件判断哪个(些)用户过期,或则通过用户点击退出删除该用户在列表的信息,然后清除会话。 首先,需要一个可公用的服务器端的存储对象,例如 SQL,文本,XML文件或则APPLICATION,为了调试方便我使用的是APPLICATION,在这个存储对象中需要存储一个可所以的字典的对象,例如数组等,这里我使用的是Hashtable,好处是Hashtable可以通过一个KEY键来索引,可以通过KEY来删除、添加等操作,而且这个KEY不仅仅是数字索引,可以是你设置的任何对象,对用户会话是否过期判断最好就用用户最后的活动时间做索引。 我在这个Hashtable中设置KEY为用户最后时间,Value设置为用户登陆名,方便显示和超时比对。(登录名做Value值的好处是同一个empid可以重复登录) 在Global.asax中的Session_End事件中不支持任何的Request 对象和Response对象,所以不能从客户端读取任何信息,这也是为什么不用COOKIE的原因。 虽然,调用Session.Abandon()方法也会触发Session_End 但是用户的Session全部销毁后才会除法Session_End,所以这时候并不能确定是那个用户触发的Session_End。因此,需要把用户的动作分为两类: 1:点击退出 调用Session.Abandon(); 2:过期超时; 这样,这个程序就分成了两个部分 1、点击退出: 先将APPLICATION中的当前会话的用户的列表信息删除,然后再清除会话。 2、过期超时:这时会触发Session_End事件,在该事件中,比对所有列表内用户信息,判断最后活动时间与当前时间,超时的就删除。 主要核心代码: Global.asax ================================================================================== //当应用程序启动的时候在Application中存储一个空的Hashtable对象 protected void Application_Start(Object sender, EventArgs e) { Hashtable ht = new Hashtable(); Application["UserName"] = ht; } //当用户会话结束的时候,比对用户最后活动时间和当前时间,判断哪些要删除,超时时间设置为应用程序中相应的会话超时时间 protected void Session_End(Object sender, EventArgs e) { Hashtable ht = (Hashtable)Application["UserName"]; foreach(DictionaryEntry item in ht) { if(DateTime.Parse(item.Key.ToString()).AddSeconds(20)<DateTime.Now) { ht.Remove(item.Key); } } } 这里应该是:AddMinutes(19),即,如果登录时间加上20分钟后还小于现在,一定是超时了。 用户登陆、退出及列表显示: =================================================================================== //获取存储对象中的Hashtable对象,并获得其存储的在线用户信息列表,并输出到页面 Hashtable ht = (Hashtable)Application["UserName"]; string str = "UserList:"; foreach(DictionaryEntry item in ht) { str+=","+item.Value; } Response.Write(str); //用户登陆,记录会话状态,并将该用户加入到在线用户信息列表中 Session["UserName"] = UserName.Text; string str = DateTime.Now.ToString(); //用于标识该用户活动时间,在用户的其他动作中需要修改该时间为用户最新活动时间 Session["key"] = str; Hashtable ht=(Hashtable)Application["UserName"]; ht.Add(str,UserName.Text); //当用户通过点击退出清除会话状态时,先在在线列表中删除该用户的信息,然后清除会话状态 Hashtable ht=(Hashtable)Application["UserName"]; ht.Remove(Session["key"].ToString()); Session.Clear(); Session.Abandon(); 由于我的sessionid没有作为key,所以我通过比对删除.(失去了hashtable的意义) protectedvoid Page_Load(object sender, EventArgs e) { ///清空Session中的内容,并停止Session if (Session["EMPID"] !=null) { Hashtable ht= (Hashtable)Application["Visitor"]; Hashtableht1=new Hashtable(); foreach(DictionaryEntry var in ht) { if (var.Value != Session["EMPID"]) ht1.Add(var.Key, var.Value); ///ht.Remove(var.Key);报错:集合已修改;可能无法执行枚举操作。 } Application.Lock(); Application["Visitor"] = ht1; Application.UnLock(); } Session.Clear(); Session.Abandon(); 以上就是主要方法,方法很简单,并可以有多种处理方式,大致思路就是这样,但是不管哪种具体的处理方式,在线的统计都将很耗服务器资源,没必要的情况下还是不用为妙