1,、用文件記錄,,每次訪問文件:死鎖問題嚴(yán)重,資源耗費(fèi)太大,。
2,、用數(shù)據(jù)庫記錄:訪問損耗大。
3,、用Global.asax和Timer實(shí)現(xiàn)統(tǒng)計(jì):比較可取,。
下面舉個(gè)例子:

總的來說,要做個(gè)在線人數(shù)統(tǒng)計(jì)簡單,,但是要做在線名單并且保存用戶的訪問日志,,就需要耗費(fèi)比較多的系統(tǒng)資源,是否劃算就難說了(我只看需求文檔,,其他不管...),;

前面用過的IHttpModule方法也不錯(cuò)

using System;
using System.ComponentModel;
using System.Web;
using System.Web.SessionState;
using System.Data;
using System.Data.OleDb;

namespace Butterfly{
/// <summary>
/// Global 的摘要說明。
/// </summary>
public class Global : System.Web.HttpApplication
{
        private static System.Threading.Timer timer;
        private const int interval = 1000 * 60 * 10;//檢查在線用戶的間隔時(shí)間
       
/// <summary>
/// 必需的設(shè)計(jì)器變量,。
/// </summary>
private System.ComponentModel.IContainer components = null;

public Global()
{
InitializeComponent();
}

protected void Application_Start(Object sender, EventArgs e)
{
            if (timer == null)
                timer = new System.Threading.Timer(new System.Threading.TimerCallback(ScheduledWorkCallback),
                    sender, 0, interval);

            DataTable userTable = new DataTable();
            userTable.Columns.Add("UserID");//用戶ID
            userTable.Columns.Add("UserName");//用戶姓名
            userTable.Columns.Add("FirstRequestTime");//第一次請求的時(shí)間
            userTable.Columns.Add("LastRequestTime");//最后一次請求的時(shí)間
            userTable.Columns.Add("ClientIP");//
            userTable.Columns.Add("ClientName");//
            userTable.Columns.Add("ClientAgent");//
            //userTable.Columns.Add("LastRequestPath");//最后訪問的頁面

            userTable.PrimaryKey = new DataColumn[]{userTable.Columns[0]};
            userTable.AcceptChanges();

            Application.Lock();
            Application["UserOnLine"] = userTable;
            Application.UnLock();
}
 
protected void Session_Start(Object sender, EventArgs e)
{

        }

        protected void Application_BeginRequest(Object sender, EventArgs e)
{
           
}

protected void Application_EndRequest(Object sender, EventArgs e)
{

}

        protected void Application_AcquireRequestState(Object sender, EventArgs e)
        {
            HttpApplication mApp = (HttpApplication)sender;
            if(mApp.Context.Session == null) return;
            if(mApp.Context.Session["UserID"]==null ) return;
            string userID = mApp.Context.Session["UserID"].ToString();
           
            DataTable userTable = (DataTable)Application["UserOnLine"];
            DataRow curRow = userTable.Rows.Find(new object[]{userID});
            if(curRow != null)
            {
                this.GetDataRowFromHttpApp(mApp,ref curRow);
            }
            else
            {
                DataRow newRow = userTable.NewRow();
                this.GetDataRowFromHttpApp(mApp,ref newRow);
                userTable.Rows.Add(newRow);
            }
            userTable.AcceptChanges();

            Application.Lock();
            Application["UserOnLine"] = userTable;
            Application.UnLock();

        }

protected void Application_AuthenticateRequest(Object sender, EventArgs e)
{
          
}

protected void Application_Error(Object sender, EventArgs e)
{
           
}

      
protected void Session_End(Object sender, EventArgs e)
{
           
}

protected void Application_End(Object sender, EventArgs e)
{
           
}

#region Web 窗體設(shè)計(jì)器生成的代碼
/// <summary>
/// 設(shè)計(jì)器支持所需的方法 - 不要使用代碼編輯器修改
/// 此方法的內(nèi)容,。
/// </summary>
private void InitializeComponent()
{   
            this.components = new System.ComponentModel.Container();
           
        }
#endregion

        private void GetDataRowFromHttpApp(HttpApplication mApp,ref DataRow mRow)
        {
            if(mApp.Context.Session == null) return;
            if(mApp.Context.Session["UserID"]==null || mApp.Context.Session["UserName"]==null) return;
            string userID = mApp.Context.Session["UserID"].ToString();
            string userName = mApp.Context.Session["UserName"].ToString();
            //string requestPath = mApp.Request.Path;
           
            if(mRow["UserID"].ToString().Length<1)
            {
                mRow["UserID"]      = userID;
                mRow["UserName"]    = userName;
                mRow["FirstRequestTime"] = System.DateTime.Now;
                mRow["ClientIP"]    = mApp.Context.Request.UserHostAddress;
                mRow["ClientName"]  = mApp.Context.Request.UserHostName;
                mRow["ClientAgent"] = mApp.Context.Request.UserAgent;
            }

            mRow["LastRequestTime"] = System.DateTime.Now;
            //mRow["LastRequestPath"] = requestPath;
           
        }

        private void ScheduledWorkCallback (object sender)
        {
            string filter = "Convert(LastRequestTime,‘System.DateTime‘) < Convert(‘" + System.DateTime.Now.AddSeconds(-interval/1000).ToString() + "‘,‘System.DateTime‘)";
            DataTable userTable = (DataTable)Application["UserOnLine"];
            DataRow[] lineOutUsers = userTable.Select(filter);
            for(int i=0;i<lineOutUsers.Length;i++)
            {
                DataRow curRow = lineOutUsers[i];
               
                //保存到數(shù)據(jù)庫
               
               curRow.Delete();
               
            }
            userTable.AcceptChanges();

            Application.Lock();
            Application["UserOnLine"] = userTable;
            Application.UnLock();
        }

      
}
}
補(bǔ)充:
    在線人數(shù)比較好做,在線名單就不好做了,,
    另外,,<sessionState> 設(shè)為InProc方式時(shí)才可以觸發(fā)SessionEnd事件,其它
          Off 指示會(huì)話狀態(tài)未啟用,。    
          StateServer 指示在遠(yuǎn)程計(jì)算機(jī)上存儲會(huì)話狀態(tài),。
          SQLServer 指示在 SQL Server 上存儲會(huì)話狀態(tài)。
    幾種方式就不能觸發(fā)SessionEnd事件;
    無論以何種解決方案,,都很難做到準(zhǔn)確,,就像QQ,對方掉線了,,你也只能過一會(huì)才知道