ASP.NET在线用户列表精确版——解决用户意外退出在线列表无法及时更新问题

【原创作者】:丛兴滋(cncxz)[E-mail:cncxz@126.com]

demo下载地址 在线监测用户在线 (把这个loginin.aspx页面设为主页运行)

在原来的基础上稍加改动了下

首先建议个类库

下面有这几个类

ActiveUser.cs

代码
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;

namespace OnlineUser 
{
    /// <summary>
    ///ActiveUser 的摘要说明
    /// </summary>
    public 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 string Ticket { get { return _ticket; } }
        public string UserName { get { return _username; } }
        public string TrueName { get { return _truename; } }
        public string RoleID { get { return _roleid; } }
        public DateTime RefreshTime { get { return _refreshtime; } }
        public DateTime ActiveTime { get { return _activetime; } }
        public string ClientIP { get { return _clientip; } }
        public ActiveUser()
        {
            //
            //TODO: 在此处添加构造函数逻辑
            //
        }
        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;
        }

    }

}

PassPort.cs

代码
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;

namespace OnlineUser
{
    /// <summary>
    ///PassPort 的摘要说明
    /// </summary>
    public class PassPort
    {
        private static DataTable _activeusers;
        private int _activeTimeout;
        private int _refreshTimeout;
        //public PassPort()
        //{
        //    //
        //    //TODO: 在此处添加构造函数逻辑
        //    //
        //}
        /// <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 = 60; }
            //自动刷新超时时间初始化 单位:分钟
            try { _refreshTimeout = int.Parse(ConfigurationSettings.AppSettings["RefreshTimeout"]); }
            catch { _refreshTimeout = 1; }
        }

        //全部用户列表
        public DataTable ActiveUsers
        {
            get { return _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();  //清除超时用户
            string strExpr;
            strExpr = byTicket ? "Ticket='" + strUserKey.Trim() + "'" : "UserName='" + strUserKey.Trim() + "'";
            DataRow[] curUser = _activeusers.Select(strExpr);
            if (curUser.Length > 0)
            {
                for (int i = 0; i < curUser.Length; i++)
                {
                    curUser[i].Delete();
                }
            }
            _activeusers.AcceptChanges();
        }
        /// <summary>
        /// 主动注销根据用户
        /// </summary>
        /// <param name="strUserName"></param>
        private void LoginOut(string strUserName)
        {
            DelTimeOut();  //清除超时用户
            string strExpr;
            strExpr = "UserName='" + strUserName.Trim() + "'";
            DataRow[] curUser = _activeusers.Select(strExpr);
            if (curUser.Length > 0)
            {
                for (int i = 0; i < curUser.Length; i++)
                {
                    curUser[i].Delete();
                }
            }
            _activeusers.AcceptChanges();
        }
        /// <summary>
        ///用户注销,根据Ticket。
        /// </summary>
        /// <param name="strTicket">要注销的用户Ticket</param>
        public void LogoutByTicket(string strTicket)
        {
            this.Logout(strTicket, false);
        }
        /// <summary>
        ///用户注销,根据Username。
        /// </summary>
        /// <param name="strTicket">要注销的用户Username</param>
        public void LoginoutByUserName(string strUser)
        {
            this.LoginOut(strUser);
        }
        /// <summary>
        ///清除超时用户。
        /// </summary>
        private bool DelTimeOut()
        {
            string strExpr = "ActiveTime < #" + DateTime.Now.AddMinutes(0 - _activeTimeout) + "# or RefreshTime < #" + DateTime.Now.AddMinutes(0 - _refreshTimeout) + "#";
            DataRow[] curUser = _activeusers.Select(strExpr);
            if (curUser.Length > 0)
            {
                for (int i = 0; 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 > 0)
            {
                for (int i = 0; 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 > 0)
            {
                for (int i = 0; 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 = _activeusers.Select(strExpr);
            if (curUser.Length > 0)
            {
                string myTicket = (string)curUser[0]["Ticket"];
                string myUser = (string)curUser[0]["UserName"];
                string myName = (string)curUser[0]["TrueName"];
                string myRoleID = (string)curUser[0]["RoleID"];
                DateTime myActiveTime = (DateTime)curUser[0]["ActiveTime"];
                DateTime myRefreshtime = (DateTime)curUser[0]["RefreshTime"];
                string myClientIP = (string)curUser[0]["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 != string.Empty);
        }

        /// <summary>
        ///按UserName判断用户是否在线。
        /// </summary>
        public bool IsOnline_byUserName(string strUserName)
        {
            return (bool)(this.SingleUser(strUserName, false).UserName != string.Empty);
        }
        /// <summary>
        /// 快速检测用户是否在线
        /// </summary>
        /// <param name="strUserName"></param>
        /// <returns></returns>
        public bool IsOnlinebyUserName(string strUserName)
        {
            string strExpr ="UserName='" + strUserName + "'";
            DataRow[] curUser = _activeusers.Select(strExpr);
            return curUser.Length > 0;
        }
    }

}

Refresh.cs

代码
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;

namespace OnlineUser 
{
    /// <summary>
    ///Refresh 的摘要说明
    /// </summary>
    public class Refresh : PlaceHolder
    {
        public Refresh()
        {
            //
            //TODO: 在此处添加构造函数逻辑
            //
        }
        /// <summary>
        /// 设置存储Ticket的Session名称,默认为Ticket。
        /// </summary>
        public virtual string SessionName
        {
            get
            {
                object obj1 = this.ViewState["SessionName"];
                if (obj1 != null) { return ((string)obj1).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);
        }
    }

}

Script.cs

代码
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Text;
namespace OnlineUser 
{
    /// <summary>
    ///Script 的摘要说明
    /// </summary>
    public class Script : PlaceHolder
    {
        public Script()
        {
            //
            //TODO: 在此处添加构造函数逻辑
            //
        }
        /// <summary>
        /// 设置js自动刷新的间隔时间,默认为25秒。
        /// </summary>
        public virtual int RefreshTime
        {
            get
            {
                object obj1 = this.ViewState["RefreshTime"];
                if (obj1 != null) { return int.Parse(((string)obj1).Trim()); }
                return 25;
            }
            set
            {
                this.ViewState["RefreshTime"] = value;
            }
        }

        protected override void Render(HtmlTextWriter writer)
        {
            //从web.config中读取xmlhttp的访问地址
            string refreshUrl = (string)ConfigurationSettings.AppSettings["refreshUrl"];
            StringBuilder st = new StringBuilder();
      
            st.Append("<script type=\"text/javascript\">\n");
            st.Append("window.attachEvent(\"onload\", " + this.ClientID + "_postRefresh);\n");
            st.Append("  var " + this.ClientID + "_xmlhttp=null;\n");
            st.Append("function " + this.ClientID + "_postRefresh(){\n");
            st.Append("  var " + this.ClientID + "_xmlhttp = new ActiveXObject(\"Msxml2.XMLHTTP\");\n");
            st.Append(this.ClientID + "_xmlhttp.Open(\"POST\", \"" + refreshUrl + "\", false);\n");
            st.Append(this.ClientID + "_xmlhttp.Send();\n");
            st.Append("var refreshStr= " + this.ClientID + "_xmlhttp.responseText;\n");
            st.Append("try {\n");
            st.Append("  var refreshStr2=refreshStr;\n");
            st.Append("}\n");
            st.Append(" catch(e) {}\n");
            st.Append(" setTimeout(\"" + this.ClientID + "_postRefresh()\"," + this.RefreshTime.ToString() + "000);\n");
            st.Append("  }\n");
            st.Append("</script>\n");

            writer.Write(writer.NewLine);
            writer.Write(st.ToString());
            writer.Write(writer.NewLine);
            base.Render(writer);
        }
    }

}