知识大全 ASP.NET优化在线用户列表精确版

Posted

篇首语:青春须早为,岂能长少年。本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 ASP.NET优化在线用户列表精确版相关的知识,希望对你有一定的参考价值。

ASP.NET优化在线用户列表精确版  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!

  最近所做的一个项目需要用到的在线用户列表 上网搜索了一下发现现有的解决方案对用户意外退出的处理均不是太理想 一般来说 用户离开系统的方式有三种 主动注销 会话超时 直接关闭浏览器 对于前两种 我们很容易便可将该用户从在线列表中清除 关键是第三种(很多用户都是直接关闭窗口的~~郁闷 ing) 程序无法捕获窗口关闭的精确时间 只能等到会话超时后在能将该用户清除出在线列表 假设我们设置会话超时时间为 分钟 而用户登陆系统随便浏 览一个页面就以关闭浏览器的方式退出的话 我们要在将近 小时后才能从在线列表中将该用户清除出去(想象一下 系统显示n多人在线 可能除了你之外其他的 n 人都关机走人了 汗一个先```) 而本文将尝试寻找一个解决方案把这种尴尬降至最低     我的大概思路是 给每在线用户增加一个RefreshTime属性 建立一个负责将当前用户的RefreshTime属性设置为当前时间的单独页面 (Refresh aspx) 然后在系统的主要页面(也可以是所有页面)中通过xmlx页面 一旦用户关闭了 与本系统相关的所有窗口 即以直接关闭浏览器的方式退出系统 那么该用户的RefreshTime属性便不会自动更新了 我们再设置一个自动刷新的超时时 间(这个要比会话超时短很多_refreshTimeout) 当发现某用户超过_refreshTimeout的时间没有自动刷新 就能判定该用户已经 以直接关闭浏览器的方式退出了     假设我们设置会话超时时间为 分钟 自动刷新超时时间为 分钟 在客户端通过xmlx超时 个人感觉 不一定正确)访问一次Refresh aspx页面 在用户登陆 用户注销 检测用户是否在线的时候都执行清理 超时用户(包括会话超时和自动刷新超时)操作 这样一来 在线用户列表的统计误差就由 分钟降至 分钟了

  ==========================================

  具体实现如下

   新建一个名为ActiveUser的类 存储单个活动用户数据 /// <summary>/// 单个在线用户数据 无法继承此类 /// </summary> public sealed class ActiveUser private readonly string _ticket;    //票据名称private readonly string _username;   //登陆用户名private readonly string _truename;   //登陆用户名private readonly string _roleid;    //角色private readonly DateTime _refreshtime; //最新刷新时间private readonly DateTime _activetime; //最新活动时间private readonly string _clientip;   //登陆IP

  public ActiveUser(string Ticket string UserName string TrueName string RoleID string ClientIP)    this _ticket=Ticket;   this _username=UserName;   this _truename=TrueName;   this _roleid=RoleID;   this _refreshtime=DateTime Now;   this _activetime=DateTime Now;   this _clientip=ClientIP;

  public ActiveUser(string Ticket string UserName string TrueName string RoleID DateTime RefreshTime DateTime ActiveTime string ClientIP)    this _ticket=Ticket;   this _username=UserName;   this _truename=TrueName;   this _roleid=RoleID;   this _refreshtime=RefreshTime;   this _activetime=ActiveTime;   this _clientip=ClientIP;

  public string Ticket getreturn _ticket; public string UserName getreturn _username; public string TrueName getreturn _truename; public string RoleID getreturn _roleid; public DateTime RefreshTime getreturn _refreshtime; public DateTime ActiveTime getreturn _activetime; public string ClientIP getreturn _clientip;

  

   新建一个名为PassPort的类 存储在线用户列表 /// <summary>/// PassPort 存储在线用户列表 /// </summary>public class PassPortprivate static DataTable _activeusers;private int _activeTimeout;private int _refreshTimeout;

  /// <summary>/// 初始化在线用户表 /// </summary> private void userstableFormat()   if(_activeusers==null)     _activeusers = new DataTable( ActiveUsers );    DataColumn myDataColumn;    System Type mystringtype;    mystringtype = System Type GetType( System String );    System Type mytimetype;    mytimetype = System Type GetType( System DateTime );    myDataColumn = new DataColumn( Ticket mystringtype);    _activeusers Columns Add(myDataColumn);    myDataColumn = new DataColumn( UserName mystringtype);    _activeusers Columns Add(myDataColumn);    myDataColumn = new DataColumn( TrueName mystringtype);    _activeusers Columns Add(myDataColumn);    myDataColumn = new DataColumn( RoleID mystringtype);    _activeusers Columns Add(myDataColumn);        myDataColumn = new DataColumn( RefreshTime mytimetype);    _activeusers Columns Add(myDataColumn);    myDataColumn = new DataColumn( ActiveTime mytimetype);    _activeusers Columns Add(myDataColumn);    myDataColumn = new DataColumn( ClientIP mystringtype);    _activeusers Columns Add(myDataColumn);     

  public PassPort()   userstableFormat(); //初始化在线用户表

   //活动超时时间初始化 单位 分钟   try _activeTimeout=int Parse(ConfigurationSettings AppSettings[ ActiveTimeout ]);    catch _activeTimeout= ;       //自动刷新超时时间初始化 单位 分钟   try _refreshTimeout=int Parse(ConfigurationSettings AppSettings[ RefreshTimeout ]);    catch _refreshTimeout= ;   

  //全部用户列表public DataTable ActiveUsers   getreturn _activeusers Copy();

  /// <summary>/// 新用户登陆 /// </summary>public void Login(ActiveUser user bool SingleLogin)   DelTimeOut(); //清除超时用户   if(SingleLogin)    //若是单人登陆则注销原来登陆的用户    this Logout(user UserName false);      DataRow myRow;   try       myRow = _activeusers NewRow();        myRow[ Ticket ] = user Ticket Trim();    myRow[ UserName ] = user UserName Trim();    myRow[ TrueName ] = +user TrueName Trim();    myRow[ RoleID ] = +user RoleID Trim();    myRow[ ActiveTime ] = DateTime Now;    myRow[ RefreshTime ] = DateTime Now;    myRow[ ClientIP ] = user ClientIP Trim();    _activeusers Rows Add(myRow);      catch(Exception e)       throw(new Exception(e Message));      _activeusers AcceptChanges();  

  /// <summary>///用户注销 根据Ticket或UserName /// </summary> private void Logout(string strUserKey bool byTicket)   DelTimeOut(); //清除超时用户   strUserKey=strUserKey Trim();   string strExpr;      strExpr =byTicket ? Ticket= + strUserKey + : UserName= + strUserKey + ;   DataRow[] curUser;   curUser = _activeusers Select(strExpr);   if (curUser Length > )       for(int i = ; i < curUser Length; i ++)         curUser[i] Delete();          _activeusers AcceptChanges();  

  /// <summary>///用户注销 根据Ticket /// </summary>/// <param name= strTicket >要注销的用户Ticket</param>public void Logout(string strTicket)   this Logout(strTicket true);

  /// <summary>///清除超时用户 /// </summary>private bool DelTimeOut()      string strExpr;      strExpr = ActiveTime < + DateTime Now AddMinutes( _activeTimeout) + or RefreshTime < +DateTime Now AddMinutes( _refreshTimeout)+ ;      DataRow[] curUser;   curUser = _activeusers Select(strExpr);   if (curUser Length > )       for(int i = ; i < curUser Length; i ++)         curUser[i] Delete();               _activeusers AcceptChanges();   return true;

  /// <summary>///更新用户活动时间 /// </summary>public void ActiveTime(string strTicket)   DelTimeOut();   string strExpr;   strExpr = Ticket= + strTicket + ;    DataRow[] curUser;   curUser = _activeusers Select(strExpr);   if (curUser Length > )       for(int i = ; i < curUser Length; i ++)         curUser[i][ ActiveTime ]=DateTime Now;     curUser[i][ RefreshTime ]=DateTime Now;          _activeusers AcceptChanges();

  /// <summary>///更新系统自动刷新时间 /// </summary>public void RefreshTime(string strTicket)   DelTimeOut();   string strExpr;   strExpr = Ticket= + strTicket + ;    DataRow[] curUser;   curUser = _activeusers Select(strExpr);   if (curUser Length > )       for(int i = ; i < curUser Length; i ++)         curUser[i][ RefreshTime ]=DateTime Now;          _activeusers AcceptChanges();

  private ActiveUser SingleUser(string strUserKey bool byTicket)   strUserKey=strUserKey Trim();   string strExpr;   ActiveUser myuser;   strExpr =byTicket ? Ticket= + strUserKey + : UserName= + strUserKey + ;    DataRow[] curUser;   curUser = _activeusers Select(strExpr);   if (curUser Length > )    string myTicket=(string)curUser[ ][ Ticket ];    string myUser=(string)curUser[ ][ UserName ];    string myName=(string)curUser[ ][ TrueName ];    string myRoleID=(string)curUser[ ][ RoleID ];        DateTime myActiveTime=(DateTime)curUser[ ][ ActiveTime ];    DateTime myRefreshtime=(DateTime)curUser[ ][ RefreshTime ];    string myClientIP =(string)curUser[ ][ ClientIP ];    myuser=new ActiveUser(myTicket myUser myName myRoleID myActiveTime myRefreshtime myClientIP);       else       myuser=new ActiveUser( );          return myuser;

  /// <summary>///按Ticket获取活动用户 /// </summary>public ActiveUser SingleUser_byTicket(string strTicket)   return this SingleUser(strTicket true);

  /// <summary>///按UserName获取活动用户 /// </summary>public ActiveUser SingleUser_byUserName(string strUserName)   return this SingleUser(strUserName false);

  /// <summary>///按Ticket判断用户是否在线 /// </summary>public bool IsOnline_byTicket(string strTicket)   return (bool)(this SingleUser(strTicket true) UserName!= );

  /// <summary>///按UserName判断用户是否在线 /// </summary>public bool IsOnline_byUserName(string strUserName)   return (bool)(this SingleUser(strUserName false) UserName!= );

   新建一个继承自PlaceHolder名为Refresh的类 执行更新自动刷新时间操作 /// <summary>/// Refresh 执行更新自动刷新时间操作 /// </summary>public class Refresh: PlaceHolder /// <summary>/// 设置存储Ticket的Session名称 默认为Ticket /// </summary>public virtual string SessionName   get    object obj = this ViewState[ SessionName ];    if (obj != null) return ((string) obj ) Trim();     return Ticket ;      set    this ViewState[ SessionName ] = value;  

  protected override void Render(HtmlTextWriter writer)    string myTicket=(string)this Page Session[this SessionName];   if(myTicket!=null)          PassPort myPass = new PassPort();    myPass RefreshTime(myTicket);    writer Write( OK +DateTime Now ToString());      else    writer Write( Sorry +DateTime Now ToString());      base Render(writer);

   新建一个继承自PlaceHolder名为Script的类 生成执行xml的js脚本

  /// <summary>/// Script 生成执行xml的js脚本 /// </summary>public class Script: PlaceHolder/// <summary>/// 设置js自动刷新的间隔时间 默认为 秒 /// </summary>public virtual int RefreshTime   get       object obj = this ViewState[ RefreshTime ];    if (obj != null)return int Parse(((string) obj ) Trim());    return ;      set           this ViewState[ RefreshTime ] = value;  

  protected override void Render(HtmlTextWriter writer)    //从nfig中读取xml的访问地址   string refreshUrl=(string)ConfigurationSettings AppSettings[ refreshUrl ];   string scriptString = @ <script language= JavaScript > +writer NewLine;   scriptString += @ window attachEvent( onload +this ClientID+@ _postRefresh); +writer NewLine;   scriptString += @ var +this ClientID+@ _xml=null; +writer NewLine;   scriptString += @ function +this ClientID+@ _postRefresh() +writer NewLine;   scriptString += @    var +this ClientID+@ _xml = new ActiveXObject( Msxml XMLHTTP ); +writer NewLine;   scriptString += @    +this ClientID+@ _xml Open( POST +refreshUrl+@ false); +writer NewLine;   scriptString += @    +this ClientID+@ _xml Send(); +writer NewLine;   scriptString += @    var refreshStr= +this ClientID+@ _xml responseText; +writer NewLine;       scriptString += @    try +writer NewLine;   scriptString += @     var refreshStr =refreshStr; +writer NewLine;   //scriptString += @     alert(refreshStr ); +writer NewLine;   scriptString += @    +writer NewLine;   scriptString += @    catch(e) +writer NewLine;   scriptString += @    setTimeout( +this ClientID+@ _postRefresh() +this RefreshTime ToString()+@ ); +writer NewLine;   scriptString += @ +writer NewLine;   scriptString += @ < ;   scriptString += @ / ;   scriptString += @ script> +writer NewLine;

  writer Write(writer NewLine);   writer Write(scriptString);   writer Write(writer NewLine);   base Render(writer);

  注意以上四个类同属于一个名为OnlineUser的工程 他们的命名空间为OnlineUser 编译生成一个dll

  下面我简单介绍一下调用方法

   新建一个名为OnlineUserDemo的 web应用程序 在vs的工具箱选项卡上右击 选择[添加/移除项] 浏览定位到OnlineUser dll 确定即可把Refresh 和Script添加到工具箱 把自动生成的WebForm aspx删除 并设置nfig<appSettings>   <add key= ActiveTimeout value= />   <add key= RefreshTimeout value= />   <add key= refreshUrl value= refresh aspx /></appSettings> 添加一个名为Online aspx的web窗体 给该窗体添加一个Script控件 一个DataGrid控件(id为DataGrid ) 两个 HyperLink控件(分别链接到login aspx和logout aspx text属性分别设置为 登陆 和 注销 ) 调整好四个控件的位 置 转到codebehind 在Page_Load中加入如下代码 string myTicket=(string)this Page Session[ Ticket ];   if(myTicket!=null)       OnlineUser PassPort myPassPort= new OnlineUser PassPort();    if(myPassPort IsOnline_byTicket(this Session[ Ticket ] ToString()))         myPassPort ActiveTime(this Session[ Ticket ] ToString());     DataGrid DataSource=myPassPort ActiveUsers;     DataGrid DataBind();        else     //若在线用户列表中找不到当前用户 则定向到注销页面     Response Redirect( Logout aspx );          else    Response Redirect( Login aspx );   添加一个名为login aspx的web窗体 给该窗体添加一个label控件(id为Label ) 设置text属性为 输入一个用户名 再添加 一个textbox控件(id为TextBox )和一个button控件(id为Button ) 调整好他们的位置 双击Button 控件转到 codebehind 为Button 的Click事件加入如下代码 if(TextBox Text Trim()== )       //不能为空    String scriptString = @ <script language=JavaScript> ;    scriptString += @ alert( 输入一个用户名\\n ); ;     scriptString += @ history go( ); ;    scriptString += @ < ;    scriptString += @ / ;    scriptString += @ script> ;    if(!this Page IsStartupScriptRegistered( Startup ))     this Page RegisterStartupScript( Startup scriptString);      else    OnlineUser PassPort myPassPort= new OnlineUser PassPort();    string myTicket=DateTime Now ToString( yyyyMMddHHmmss );    string myUser=TextBox Text Trim();    string myClintIP=this Request UserHostAddress;    this Session[ Ticket ]=myTicket;    OnlineUser ActiveUser myActiveUser=new OnlineUser ActiveUser(myTicket myUser myUser test myClintIP);    myPassPort Login(myActiveUser true);    Response Redirect( Online aspx );   添加一个名为logout aspx的web窗体 给该窗体添加一个HyperLink控件 指向login aspx text属性设置为 重登陆 转到codebehind 在Page_Load中加入如下代码 OnlineUser PassPort myPassPort= new OnlineUser PassPort();myPassPort Logout(this Session[ Ticket ] ToString());this Session[ Ticket ]= ;

   添加一个名为Refresh txt的文本文件 设置其内容为 <%@ Register TagPrefix= cc Namespace= OnlineUser Assembly= OnlineUser %><%@ Page %><cc :Refresh id= myRefresh runat= server ></cc :Refresh>把Refresh txt改名为Refresh aspx

   编译生成工程

  ===============================================下面进行功能测试

   打开浏览器 在地址栏输入x 输入一个用户名(假设是test )登陆 自动转到online aspx页面 找同网段的另外一台机器(设你的机器为a 这台机器为b) 重复执行第一步

输入一个用户名(假设是test )登陆 自动转到online aspx页面 在b机器不断刷新online aspx 若发现test 用户RefreshTime每过 秒自动更新一次而ActiveTime不变(这个时候a机器不要刷新页面啊) 则证明a机器的自动刷新生效 在a机器不断刷新online aspx 若发现test 用户RefreshTime每过 秒自动更新一次而ActiveTime不变(这个时候b机器不要刷新页面啊) 则证明b机器的自动刷新生效 直接关闭一台机器(假设是a)上的online aspx浏览窗口 在另一台机器(就是b啦)上刷新online aspx 若发现 分钟后test 掉线在线用户只剩下test 证明通过_refreshTimeout清除在线用户成功 若 三步正常 则大功告成 否则就再调试调试~~ cha138/Article/program/net/201311/13149

相关参考

知识大全 用ASP.NET设计高效邮件列表

用ASP.NET设计高效邮件列表  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  一个吸引人的功能

知识大全 ASP.NET项目开发指南:博客列表(1)

ASP.NET项目开发指南:博客列表(1)  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  &nb

知识大全 ASP.NET项目开发指南:博客列表(2)

ASP.NET项目开发指南:博客列表(2)  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  &nb

知识大全 ASP.NET项目开发指南:新闻列表[1]

ASP.NET项目开发指南:新闻列表[1]  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  &nb

知识大全 ASP.NET项目开发指南:新闻列表[2]

ASP.NET项目开发指南:新闻列表[2]  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  ST_

知识大全 ASP.NET 2.0移动开发之列表控件

ASP.NET2.0移动开发之列表控件  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!概述  在很多

知识大全 ASP.NET入门教程 1.7.9 错误列表窗口[2]

ASP.NET入门教程1.7.9错误列表窗口[2]  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!&

知识大全 ASP.NET入门教程 1.7.9 错误列表窗口[3]

ASP.NET入门教程1.7.9错误列表窗口[3]  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!&

知识大全 ASP.NET入门教程 1.7.9 错误列表窗口[1]

ASP.NET入门教程1.7.9错误列表窗口[1]  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!&

知识大全 ASP.NET入门教程 7.4.1 数据绑定选项列表[1]

ASP.NET入门教程7.4.1数据绑定选项列表[1]  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧