一分心灵的宁静

在滚滚红尘,繁杂人世里,能够保持一分心灵的宁静,随时回到自己的内心深处,细细品味生命的奥妙,无疑是一种修身养性的人生境界

导航

解决用户意外退出在线列表无法及时更新问题

Posted on 2006-02-11 13:19  有缘无份  阅读(387)  评论(1编辑  收藏  举报

1、 新建一个名为ActiveUser的类,存储单个活动用户数据。

 1/// <summary>
 2 /// 单个在线用户数据,无法继承此类。
 3 /// </summary> 

 4 public sealed class ActiveUser
 5 {  
 6  private readonly string _ticket;    //票据名称
 7  private readonly string _username;   //登陆用户名
 8  private readonly string _truename;   //登陆用户名
 9  private readonly string _roleid;    //角色
10  private readonly DateTime _refreshtime;  //最新刷新时间
11  private readonly DateTime _activetime;  //最新活动时间
12  private readonly string _clientip;   //登陆IP
13  
14  public ActiveUser(string Ticket,string UserName,string TrueName,string RoleID,string ClientIP) {
15   this._ticket=Ticket;
16   this._username=UserName;
17   this._truename=TrueName;
18   this._roleid=RoleID;
19   this._refreshtime=DateTime.Now;
20   this._activetime=DateTime.Now;
21   this._clientip=ClientIP;
22  }

23
24  public ActiveUser(string Ticket,string UserName,string TrueName,string RoleID,DateTime RefreshTime,DateTime ActiveTime,string ClientIP)  {
25   this._ticket=Ticket;
26   this._username=UserName;
27   this._truename=TrueName;
28   this._roleid=RoleID;
29   this._refreshtime=RefreshTime;
30   this._activetime=ActiveTime;
31   this._clientip=ClientIP;
32  }

33  
34  public string Ticket  get{return _ticket;}  }
35  public string UserName  get{return _username;}  }
36  public string TrueName  get{return _truename;}  }
37  public string RoleID  get{return _roleid;}  }
38  public DateTime RefreshTime get{return _refreshtime;} }
39  public DateTime ActiveTime get{return _activetime;} }
40  public string ClientIP  get{return _clientip;}  }
41
42 }

43
44
2、 新建一个名为PassPort的类,存储在线用户列表。
  1/// <summary>
  2 /// PassPort 存储在线用户列表。
  3 /// </summary>

  4 public class PassPort
  5 {
  6  private  static  DataTable  _activeusers;
  7  private  int  _activeTimeout;
  8  private  int  _refreshTimeout;
  9
 10  /// <summary>
 11  /// 初始化在线用户表。
 12  /// </summary> 

 13  private void userstableFormat()
 14  {
 15   if(_activeusers==null{
 16    _activeusers  =  new  DataTable("ActiveUsers");
 17    DataColumn  myDataColumn;
 18    System.Type mystringtype;
 19    mystringtype = System.Type.GetType("System.String");
 20    System.Type mytimetype;
 21    mytimetype = System.Type.GetType("System.DateTime");
 22    myDataColumn  =  new  DataColumn("Ticket",mystringtype);
 23    _activeusers.Columns.Add(myDataColumn);
 24    myDataColumn  =  new  DataColumn("UserName",mystringtype);
 25    _activeusers.Columns.Add(myDataColumn);
 26    myDataColumn  =  new  DataColumn("TrueName",mystringtype);
 27    _activeusers.Columns.Add(myDataColumn);
 28    myDataColumn  =  new  DataColumn("RoleID",mystringtype);
 29    _activeusers.Columns.Add(myDataColumn);    
 30    myDataColumn  =  new  DataColumn("RefreshTime",mytimetype);
 31    _activeusers.Columns.Add(myDataColumn);
 32    myDataColumn  =  new  DataColumn("ActiveTime",mytimetype);
 33    _activeusers.Columns.Add(myDataColumn);
 34    myDataColumn  =  new  DataColumn("ClientIP",mystringtype);
 35    _activeusers.Columns.Add(myDataColumn);   
 36   }

 37  }

 38
 39  public PassPort()
 40  {
 41   userstableFormat(); //初始化在线用户表
 42   //活动超时时间初始化 单位:分钟
 43   try { _activeTimeout=int.Parse(ConfigurationSettings.AppSettings["ActiveTimeout"]); }
 44   catch{ _activeTimeout=60; }   
 45   //自动刷新超时时间初始化 单位:分钟
 46   try { _refreshTimeout=int.Parse(ConfigurationSettings.AppSettings["RefreshTimeout"]); }
 47   catch{ _refreshTimeout=1; }   
 48  }

 49
 50  //全部用户列表
 51  public  DataTable  ActiveUsers
 52  {
 53   get{return  _activeusers.Copy();}
 54  }

 55  
 56  /// <summary>
 57  /// 新用户登陆。
 58  /// </summary>

 59  public void Login(ActiveUser user,bool SingleLogin)
 60  {
 61   DelTimeOut();  //清除超时用户
 62   if(SingleLogin){
 63    //若是单人登陆则注销原来登陆的用户
 64    this.Logout(user.UserName,false);
 65   }

 66   DataRow myRow;
 67   try
 68   {
 69    myRow  =  _activeusers.NewRow();    
 70    myRow["Ticket"]  =  user.Ticket.Trim();
 71    myRow["UserName"]  =  user.UserName.Trim();
 72    myRow["TrueName"]  =  ""+user.TrueName.Trim();
 73    myRow["RoleID"]  =  ""+user.RoleID.Trim();
 74    myRow["ActiveTime"]  =  DateTime.Now;
 75    myRow["RefreshTime"]  =  DateTime.Now;
 76    myRow["ClientIP"]  =  user.ClientIP.Trim();
 77    _activeusers.Rows.Add(myRow);
 78   }

 79   catch(Exception  e)
 80   {
 81    throw(new  Exception(e.Message));
 82   }
  
 83   _activeusers.AcceptChanges();
 84   
 85  }

 86
 87  /// <summary>
 88  ///用户注销,根据Ticket或UserName。
 89  /// </summary> 

 90  private void Logout(string strUserKey,bool byTicket)
 91  {
 92   DelTimeOut();  //清除超时用户
 93   strUserKey=strUserKey.Trim();
 94   string  strExpr;   
 95   strExpr =byTicket ? "Ticket='" + strUserKey +"'" : "UserName='" + strUserKey + "'";
 96   DataRow[]  curUser;
 97   curUser  =  _activeusers.Select(strExpr);
 98   if  (curUser.Length  >0  )
 99   {
100    for(int  i  =  0;  i  <  curUser.Length;  i  ++)
101    {
102     curUser[i].Delete();
103    }

104   }

105   _activeusers.AcceptChanges();   
106  }

107
108  /// <summary>
109  ///用户注销,根据Ticket。
110  /// </summary>
111  /// <param name="strTicket">要注销的用户Ticket</param>

112  public void Logout(string strTicket){
113   this.Logout(strTicket,true);
114  }

115
116  /// <summary>
117  ///清除超时用户。
118  /// </summary>

119  private  bool DelTimeOut()
120  {   
121   string  strExpr;   
122   strExpr = "ActiveTime < '" + DateTime.Now.AddMinutes( 0 - _activeTimeout) + "'or RefreshTime < '"+DateTime.Now.AddMinutes( 0 - _refreshTimeout)+"'";   
123   DataRow[]  curUser;
124   curUser  =  _activeusers.Select(strExpr);
125   if  (curUser.Length  >0  )
126   {
127    for(int  i  =  0;  i  <  curUser.Length;  i  ++)
128    {
129     curUser[i].Delete();     
130    }

131   }

132   _activeusers.AcceptChanges();
133   return  true;
134  }

135
136  /// <summary>
137  ///更新用户活动时间。
138  /// </summary>

139  public  void  ActiveTime(string  strTicket)
140  {
141   DelTimeOut();
142   string  strExpr;
143   strExpr  =  "Ticket='"  +  strTicket  +  "'";  
144   DataRow[]  curUser;
145   curUser  =  _activeusers.Select(strExpr);
146   if  (curUser.Length  >0  )
147   {
148    for(int  i  =  0;  i  <  curUser.Length;  i  ++)
149    {
150     curUser[i]["ActiveTime"]=DateTime.Now;
151     curUser[i]["RefreshTime"]=DateTime.Now;
152    }

153   }

154   _activeusers.AcceptChanges();
155  }

156
157  /// <summary>
158  ///更新系统自动刷新时间。
159  /// </summary>

160  public  void  RefreshTime(string  strTicket)
161  {
162   DelTimeOut();
163   string  strExpr;
164   strExpr  =  "Ticket='"  +  strTicket  +  "'";  
165   DataRow[]  curUser;
166   curUser  =  _activeusers.Select(strExpr);
167   if  (curUser.Length  >0  )
168   {
169    for(int  i  =  0;  i  <  curUser.Length;  i  ++)
170    {
171     curUser[i]["RefreshTime"]=DateTime.Now;
172    }

173   }

174   _activeusers.AcceptChanges();
175  }

176
177  private ActiveUser SingleUser(string strUserKey,bool byTicket)
178  {
179   strUserKey=strUserKey.Trim();
180   string  strExpr;
181   ActiveUser myuser;
182   strExpr =byTicket ? "Ticket='" + strUserKey +"'" : "UserName='" + strUserKey + "'"
183   DataRow[]  curUser;
184   curUser  =  _activeusers.Select(strExpr);
185   if  (curUser.Length  >0  )
186{
187    string myTicket=(string)curUser[0]["Ticket"];
188    string myUser=(string)curUser[0]["UserName"];
189    string myName=(string)curUser[0]["TrueName"];
190    string myRoleID=(string)curUser[0]["RoleID"];    
191    DateTime myActiveTime=(DateTime)curUser[0]["ActiveTime"];
192    DateTime myRefreshtime=(DateTime)curUser[0]["RefreshTime"];
193    string myClientIP =(string)curUser[0]["ClientIP"];
194    myuser=new ActiveUser(myTicket,myUser,myName,myRoleID,myActiveTime,myRefreshtime,myClientIP);  
195   }

196   else
197   {
198    myuser=new ActiveUser("","","","","");    
199   }

200   return  myuser;
201  }

202
203  /// <summary>
204  ///按Ticket获取活动用户。
205  /// </summary>

206  public ActiveUser SingleUser_byTicket(string strTicket)
207  {
208   return this.SingleUser(strTicket,true);
209  }

210
211  /// <summary>
212  ///按UserName获取活动用户。
213  /// </summary>

214  public ActiveUser SingleUser_byUserName(string strUserName)
215  {
216   return this.SingleUser(strUserName,false);
217  }

218
219  /// <summary>
220  ///按Ticket判断用户是否在线。
221  /// </summary>

222  public bool IsOnline_byTicket(string strTicket)
223  {
224   return (bool)(this.SingleUser(strTicket,true).UserName!="");
225  }

226
227  /// <summary>
228  ///按UserName判断用户是否在线。
229  /// </summary>

230  public bool IsOnline_byUserName(string strUserName)
231  {
232   return (bool)(this.SingleUser(strUserName,false).UserName!="");
233  }

234}

235
236
3、 新建一个继承自PlaceHolder名为Refresh的类,执行更新自动刷新时间操作。
 1/// <summary>
 2 /// Refresh 执行更新自动刷新时间操作。
 3 /// </summary>

 4 public class Refresh: PlaceHolder 
 5 {
 6  /// <summary>
 7  /// 设置存储Ticket的Session名称,默认为Ticket。
 8  /// </summary>

 9  public virtual string SessionName
10  {
11   get{
12    object obj1 = this.ViewState["SessionName"];
13    if (obj1 != null)return ((string) obj1).Trim(); }
14    return "Ticket";
15   }

16   set{
17    this.ViewState["SessionName"= value;
18   }

19  }

20
21  protected override void Render(HtmlTextWriter writer) 
22  {
23   string myTicket=(string)this.Page.Session[this.SessionName];
24   if(myTicket!=null)
25   {   
26    PassPort myPass = new PassPort();
27    myPass.RefreshTime(myTicket);
28    writer.Write("OK:"+DateTime.Now.ToString());
29   }

30   else{
31    writer.Write("Sorry:"+DateTime.Now.ToString());
32   }

33   base.Render(writer);
34 }

35}

36
37
4、 新建一个继承自PlaceHolder名为Script的类,生成执行xmlhttp的js脚本。。
 1/// <summary>
 2 /// Script 生成执行xmlhttp的js脚本。
 3 /// </summary>

 4 public class Script: PlaceHolder
 5 {
 6  /// <summary>
 7  /// 设置js自动刷新的间隔时间,默认为25秒。
 8  /// </summary>

 9  public virtual int RefreshTime
10  {
11   get
12   {
13    object obj1 = this.ViewState["RefreshTime"];
14    if (obj1 != null){return int.Parse(((string) obj1).Trim());}
15    return 25;
16   }

17   set
18   {    
19    this.ViewState["RefreshTime"= value;
20   }

21  }

22
23  protected override void Render(HtmlTextWriter writer) 
24  {
25   //从web.config中读取xmlhttp的访问地址
26   string refreshUrl=(string)ConfigurationSettings.AppSettings["refreshUrl"];
27   string scriptString = @" <script language=""JavaScript"">"+writer.NewLine;
28   scriptString += @"  window.attachEvent(""onload"", "+this.ClientID+@"_postRefresh);"+writer.NewLine;
29   scriptString += @"  var "+this.ClientID+@"_xmlhttp=null;"+writer.NewLine;
30   scriptString += @"  function "+this.ClientID+@"_postRefresh(){"+writer.NewLine;
31   scriptString += @"   var "+this.ClientID+@"_xmlhttp = new ActiveXObject(""Msxml2.XMLHTTP"");"+writer.NewLine;
32   scriptString += @"   "+this.ClientID+@"_xmlhttp.Open(""POST"", """+refreshUrl+@""", false);"+writer.NewLine;
33   scriptString += @"   "+this.ClientID+@"_xmlhttp.Send();"+writer.NewLine;
34   scriptString += @"   var refreshStr= "+this.ClientID+@"_xmlhttp.responseText;"+writer.NewLine;
35    
36   scriptString += @"   try {"+writer.NewLine;
37   scriptString += @"    var refreshStr2=refreshStr;"+writer.NewLine;
38   //scriptString += @"    alert(refreshStr2);"+writer.NewLine;
39   scriptString += @"   }"+writer.NewLine;
40   scriptString += @"   catch(e) {}"+writer.NewLine;
41   scriptString += @"   setTimeout("""+this.ClientID+@"_postRefresh()"","+this.RefreshTime.ToString()+@"000);"+writer.NewLine;
42   scriptString += @"  }"+writer.NewLine;
43   scriptString += @"<";
44   scriptString += @"/";
45   scriptString += @"script>"+writer.NewLine;
46
47   writer.Write(writer.NewLine);
48   writer.Write(scriptString);
49   writer.Write(writer.NewLine);
50   base.Render(writer);
51  }

52 }

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

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

 

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

1、 新建一个名为OnlineUserDemo的asp.net web应用程序
2、 在vs的工具箱选项卡上右击,选择[添加/移除项],浏览定位到OnlineUser.dll,确定即可把Refresh 和Script添加到工具箱。
3、 把自动生成的WebForm1.aspx删除,并设置web.config

1<appSettings>
2   <add key="ActiveTimeout" value="30" />
3   <add key="RefreshTimeout" value="1" />
4   <add key="refreshUrl" value="refresh.aspx" />
5 </appSettings
4、 添加一个名为Online.aspx的web窗体,给该窗体添加一个Script控件,一个DataGrid控件(id为DataGrid1),两个HyperLink控件(分别链接到login.aspx和logout.aspx,text属性分别设置为“登陆”和“注销”),调整好四个控件的位置,转到codebehind,在Page_Load中加入如下代码:
 1string myTicket=(string)this.Page.Session["Ticket"];
 2   if(myTicket!=null)
 3   {
 4    OnlineUser.PassPort myPassPort= new OnlineUser.PassPort();
 5    if(myPassPort.IsOnline_byTicket(this.Session["Ticket"].ToString()))
 6    {
 7     myPassPort.ActiveTime(this.Session["Ticket"].ToString());
 8     DataGrid1.DataSource=myPassPort.ActiveUsers;
 9     DataGrid1.DataBind();
10    }

11    else{
12     //若在线用户列表中找不到当前用户,则定向到注销页面
13     Response.Redirect("Logout.aspx");
14    }

15   }

16   else{
17    Response.Redirect("Login.aspx");
18   }

19
5、 添加一个名为login.aspx的web窗体,给该窗体添加一个label控件(id为Label1),设置text属性为“输入一个用户名”,再添加一个textbox控件(id为TextBox1)和一个button控件(id为Button1),调整好他们的位置,双击Button1控件转到codebehind,为Button1的Click事件加入如下代码:
 1if(TextBox1.Text.Trim()=="")
 2   {
 3    //不能为空
 4    String scriptString = @"<script language=JavaScript>";
 5    scriptString += @"alert(""输入一个用户名\n"");"
 6    scriptString += @"history.go(-1);";
 7    scriptString += @"<";
 8    scriptString += @"/";
 9    scriptString += @"script>";
10    if(!this.Page.IsStartupScriptRegistered("Startup"))
11     this.Page.RegisterStartupScript("Startup", scriptString);
12   }

13   else{
14    OnlineUser.PassPort myPassPort= new OnlineUser.PassPort();
15    string myTicket=DateTime.Now.ToString("yyyyMMddHHmmss");
16    string myUser=TextBox1.Text.Trim();
17    string myClintIP=this.Request.UserHostAddress;
18    this.Session["Ticket"]=myTicket;
19    OnlineUser.ActiveUser myActiveUser=new OnlineUser.ActiveUser(myTicket,myUser,myUser,"test",myClintIP);
20    myPassPort.Login(myActiveUser,true);
21    Response.Redirect("Online.aspx");
22   }

23
6、 添加一个名为logout.aspx的web窗体,给该窗体添加一个HyperLink控件,指向login.aspx,text属性设置为“重登陆”转到codebehind,在Page_Load中加入如下代码:
1OnlineUser.PassPort myPassPort= new OnlineUser.PassPort();
2  myPassPort.Logout(this.Session["Ticket"].ToString());
3 this.Session["Ticket"]="";
4
7、 添加一个名为Refresh.txt的文本文件,设置其内容为:
1<%@ Register TagPrefix="cc2" Namespace="OnlineUser" Assembly="OnlineUser" %>
2<%@ Page %>
3<cc2:Refresh id="myRefresh" runat="server"></cc2:Refresh>
4把Refresh.txt改名为Refresh.aspx
5

8、 编译生成工程。

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


下面进行功能测试:

1、 打开浏览器,在地址栏输入
http://你机器的IP地址/onlineuserdemo/Login.aspx
2、 输入一个用户名(假设是test1)登陆,自动转到online.aspx页面
3、 找同网段的另外一台机器(设你的机器为a,这台机器为b),重复执行第一步。
4、 输入一个用户名(假设是test2)登陆,自动转到online.aspx页面
5、 在b机器不断刷新online.aspx,若发现test1用户RefreshTime每过25秒自动更新一次而ActiveTime不变(这个时候a机器不要刷新页面啊),则证明a机器的自动刷新生效。
6、 在a机器不断刷新online.aspx,若发现test2用户RefreshTime每过25秒自动更新一次而ActiveTime不变(这个时候b机器不要刷新页面啊),则证明b机器的自动刷新生效。
7、 直接关闭一台机器(假设是a)上的online.aspx浏览窗口,在另一台机器(就是b啦)上刷新online.aspx,若发现1分钟后test1掉线在线用户只剩下test2,证明通过_refreshTimeout清除在线用户成功。
8、 若5、6、7三步正常,则大功告成,否则就再调试调试~~