在ASP.NET梦工厂群中,有朋友寻网站当前在线人数和所有访问次数的代码,因为正好看到书上有这个例子就应了下来,结果却小弄了好一阵才搞定,不过还真有些需要注意的问题,在此总结,希望和大家共同交流。
    原本在VS2003中默认已经建立的web.config文件和Global.asax,在05下都需要手动添加了,下面就是添加 Global.asax 的界面:手动添加Global.asax

   
下面是默认生成的Global.asax的代码,和03也有了些许不同,函数的声明也有了小变化。
<%@ Application Language="C#" %>
<script runat="server">
    void Application_Start(object sender, EventArgs e)
    {
        // Code that runs on application startup
    }   
    void Application_End(object sender, EventArgs e)
    {
        //  Code that runs on application shutdown
    }       
    void Application_Error(object sender, EventArgs e)
    {
        // Code that runs when an unhandled error occurs
    }
    void Session_Start(object sender, EventArgs e)
    {
        // Code that runs when a new session is started
    }
    void Session_End(object sender, EventArgs e)
    {
        // Code that runs when a session ends.
        // Note: The Session_End event is raised only when the sessionstate mode
        // is set to InProc in the Web.config file. If session mode is set to StateServer
        // or SQLServer, the event is not raised.
    }      
</script>
    这里需要注意的是 Session_End 事件,只有 InProc 模式支持该事件,也就是说,只有将会话数据存储在 ASP.NET 辅助进程中时才支持该事件。它标志着会话的结束,并用于执行终止该会话所需的所有清除代码。对于要引发的 Session_End 事件来说,必须首先存在会话状态,这意味着必须在该会话状态中存储一些数据,并且必须至少完成一个请求。如果会话状态属性 Mode 为 StateServer 或 SQLServer,则忽略 Global.asax 文件中的 Session_End 事件。如果会话状态属性 Mode 设置为 Custom,则由自定义会话状态存储提供程序决定是否支持 Session_End 事件。
     会话状态的配置是通过设置Web.config文件的<sessionState>节来实现的。下面介绍一下进程内模式的配置方法,它也是默认的会话状态模式。若要使用进程内模式,请将 <sessionState> 元素的 mode 属性设置为 Inproc。
下面显示了进程内模式的一个配置设置示例。
<configuration>
    <system.web>
        <sessionState mode="Inproc"
                      cookieless="false"
                      timeout="20"/>
        </sessionState>
    </system.web>
</configuration>
    下面是我的Global.asax的完整代码,其中在线统计的部分借鉴了 MSDN 中的方法,而没有使用 Session 对象,所有访问次数的统计是采用了读写文件的方式,需要在应用程序中加一个 Counter.txt 文本文件。
<%@ Application Language="C#" %>
<%@ Import Namespace="System.IO" %>
<script runat="server">
    void Application_Start(object sender, EventArgs e)
    {
        Application["UsersOnline"] = 0;
        int count = 0;
        StreamReader srd;
        //取得文件的实际路径
        string file_path = Server.MapPath("counter.txt");
        //打开文件进行读取
        srd = File.OpenText(file_path);
        while (srd.Peek() != -1)
        {
            string str = srd.ReadLine();
            count = Int32.Parse(str);
        }
        object obj = count;
        Application["TotalCount"] = obj;
        srd.Close();
    }
   
    void Application_End(object sender, EventArgs e)
    {
        int count = 0;
        count = (int)Application["TotalCount"];
        string file_path = Server.MapPath("counter.txt");
        StreamWriter fs = new StreamWriter(file_path, false);
        fs.WriteLine(count);
        fs.Close();
    }
       
    void Application_Error(object sender, EventArgs e)
    {
        // Code that runs when an unhandled error occurs
    }
    void Session_Start(object sender, EventArgs e)
    {
        Application.Lock();
        Application["UsersOnline"] = (int)Application["UsersOnline"] + 1;
        //访问总数加1
        int count = 0;
        count = (int)Application["TotalCount"];
        count = count + 1;
        Application["TotalCount"] = count;
        //将数据记录写入文件
        string file_path = Server.MapPath("counter.txt");
        try
        {
            StreamWriter fs = new StreamWriter(file_path, false);
            fs.WriteLine(count);
            fs.Close();
        }
        catch (Exception ex)
        {
            Application["Error"] = ex.Message;
        }
        Application.UnLock();
    }
    void Session_End(object sender, EventArgs e)
    {
        Application.Lock();
        Application["UsersOnline"] = (int)Application["UsersOnline"] - 1;
        Application.UnLock();
    }
      
</script>
下面是我的测试页面 WebCount.aspx,简单地在页面上加两个lable显示人数即可:
using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
public partial class WebCount : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        if (!Page.IsPostBack)
        {
            if (Application["UsersOnline"] != null)
            {
                //获取当前在线人数
                currentUserNum.Text = Application["UsersOnline"].ToString();
            }
            if (Application["TotalCount"] != null)
            {
                //获取网站总访问人数
                totalUserNum.Text = Application["TotalCount"].ToString();
            }
        }
    }
}
    具体的有关会话管理的知识可以查看帮助,这里仅就一个问题和大家讨论,路过者有熟悉的请留言或加QQ:65127444
程序里之所以都使用了 Application ,而没有使用 Session,是因为我使用 <ASP.NET 网络数据库开发实例精解> 一书中第10章的模块 时调试未成功 :(
    下面的代码是这本书中使用 Session 的,可我经过调试,即使多用户同时访问,也还是显示当前在线为1。
它的实现方式是:将以下代码写在 Session_Start 中,然后在 Session_End 中再减1。
   if(Session["CurrentCount"] != null)
   {
    Session["CurrentCount"] = Int32.Parse(Session["CurrentCount"].ToString()) + 1;
   }
   else
   {
    Session["CurrentCount"] = 1;
   }
    然后将 Page_Load 中显示当前人数的Application["UsersOnline"].ToString() 改为 Session["CurrentCount"].ToString(),不管几个用户同时访问,每个人的浏览器显示的当前人数均为 1。
    呵呵,总结到这里,忽然醒悟了,看来总结也是好处不少啊,呵呵,先说说我写到这里时的理解吧:对象 Session 仅被单个用户所共享,所以,每个用户登录时,Session["CurrentCount"] 都为空,所以,都被赋值为1了,似乎这也充分说明了一些写计算机书籍的人的不负责任,呵呵,随便凑合能看就出版了,代码正确率很低啊!至少,我测试得到的不是想要的结果,也许,我个人的理解有偏差?高手路过的请指点一下了!
    当然,利用读写文件的方式,还可以统计最大在线人数。就是将Application["UsersOnline"]的值和用于保存最大在线人数的文件(如:maxcount.txt)中的值比较,大于则重写,小于则不改变即可。有兴趣的可以自己实现一下,呵呵,好累!
    继续努力了一下,呵呵,最大在线人数的也有了:
        //最大在线人数
        DataSet objDataSet = new DataSet();
        objDataSet.ReadXml(Server.MapPath("count.xml"));
        int maxCount = Convert.ToInt32(objDataSet.Tables["MyCount"].Rows[0]["MaxCount"]);
        Application["MaxCount"] = maxCount;
        if (maxCount < (int)Application["UsersOnline"])    //如果MaxCount标签里面的值小于当前在线人数的值,就存入
            objDataSet.Tables["MyCount"].Rows[0]["MaxCount"] = (int)Application["UsersOnline"];
            objDataSet.WriteXml(Server.MapPath("count.xml"));
附:count.xml:
<?xml version="1.0" standalone="yes"?>
<MyCount>
  <MaxCount>0</MaxCount>
</MyCount>