ASP.NET通过Appliaction和Session统计在人数和历史访问量
目录
背景:
Appliaction:
Session:
过程:
数据库:
Application_Start:
Session_Start:
Session_End:
Application_End:
背景:
事件 | 何时激发 |
Application_Start | 在调用当前应用程序目录(或子目录)的第一个ASP.NET页面时激发 |
Applicaiotn_End | 在应用程序最后一次会话结束时激发,此外在使用Internet服务管理器管理单元停止,Web应用程序时也会激发 |
Application_BeginRequest | 在每次页面请求开始时(理论上,在加载或刷新页面)激发 |
Application_EndRequest | 在每次页面请求结束时(即每次在浏览器上执行该页面时)激发 |
Session_Start | 在每次新的会话开始时激发 |
Session_End | 在会话结束时激发 |
Appliaction:
Application(通常写作Applicaiton)和Session在Wweb开发中各自扮演重要的角色,它们之间既有关联也有区别
Application对象是一个应用级别的对象,主要用于存储和访问来自任何页面的变量,它表示用来保存所有用户(浏览器)共享的数据,直到Web服务器或Pc关闭为止。由于所有的用户共享一个Applicaiton对象,因此它可以用来在所有用户之间共享信息,并可以在Web应用程序运行期间持久地保持数据,如果不加以限制,所有的客户都可以访问这个对象。
Session:
存储用户信息
优点→-包含用户信息
-在会话中跟踪和监视用户信息
-会话期满后销毁对象
对象则与特定的用户关联,每个用户都有自己的Session对象,Session用于存储特定用户ADO会话所需的信息,主要用于弥补HTTP协议的不足,因为HTTP协议是一种无状态的协议。Session对象从用户到达某个特定的Web页开始存在,直到该用过户离开Web站点或在程序中利用代码终止某个Session为止,Session的存储是有时效性的,超过设置时间后会被服务器从内存中清除
总的来说Appliction和 Session都是ASP文件公用的对象,用于在多个网页之间保留和使用一些公用信息。它们主要区别于作用的范围和应用场景:Applicaiotn是所有用户共享的,用于全局范围内数据持久化;而Session则是针对单个用户的,用于存储特定用户的会话信息
过程:
数据库:
-- 首先创建一个数据库:
CREATE DATABASE countpeople; -- 创建数据库
USE countpeople; -- 转到数据库中
-- 创建表
CREATE TABLE countepeople (
num INT -- 新建字段
);
-- 插入一条数值为0的记录
INSERT INTO countepeople VALUES (0);
在ASP.NE中统计在线人数和历史访问人数需要使用四个事件:Applicaiton_Start(),Application_End(),Session_Start()和Session_End();在ASP.NET应用程序启动时,会先触发Application_Start()事件,这是因为Application_Start()事件是在应用程序的全局.asax文件中定义的,并且它是在应用程序开始时被调用的特殊事件。
Application_Start:
在ASP.NET中,当应用程序启动时,会首先触发Global.asax的Applicaiotn_Start()事件,在这个事件中,我们可以增加两个Applicaiotn变量来表示整个程序的公共变量:totalCouont(用来表示总的访问量)和onlineCount(用来表示当前在线人数)
void Application_Start(object sender, EventArgs e)
{
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
//上面两行代码,分别用于注册应用程序的路由河 资源捆绑配置,以便于管理 网站的ULR路由和静态资源文件
SqlConnection con = new SqlConnection("server=.;database=countPeople;uid=sa;pwd=123;");
//数据库连接对象
con.Open();
//打开数据库连接
SqlCommand cmd = new SqlCommand("select * from countPeople", con);
//创建SQL查询命令,用于执行查询数据库中countPeple表的所有内容
int count = Convert.ToInt32(cmd.ExecuteScalar());
//执行SQL查询命令并获得命令并获取查询结果的第一行第一列的值,即数据库中的访问人数,并将其转换为整数类型
con.Close();
//关闭数据库
Application["total"] = count;
//查询得到的访问人数存储在应用程序的Application对象中,使用名为"total"的变量表示当前在线人数
Application["online"] = 0;
}
//初始化在线人数未0,并将其存储在应用程序的Applicaiton对象中,使用名为"online"的变量来表示在线人数
Session_Start:
当每个客户端(浏览器)首次访问服务器时,会触发Session_Start事件,在这个事件中,我们需要让两个"公共变量"totalCount和onlineCount各自自增1",然后,当有多个客户端同时访问时,如果多个请求试图同时更新这些变量,就可能发生数据竞争,导致结果不准确,所以我们为了避免这种情况,我们可以使用Application.Lock()方法来锁定Application对象,确保在任何时候只有一个请求能够修改totalCount和onlineCount。当Applicaiont.Lock()被调用后,任何尝试读取或修改Applicaiont对象的操作都将被阻塞,直到Applicaiotn.UnLock()被调用。这样,就可以保证线程安全地更新这些变量。
void Session_Start(object sender, EventArgs e)
{
Session.Timeout = 1;
//通过设置Session.Timeout=1,将会话时间设置超过一分钟。这意味如果月用户在一分钟内没有活动,则其会话将过期并清除
Application.Lock();
//使用Application.Lock()方法锁定Applicaiton对象,以确保在同一时刻只有一个请求可以修改Applicaiton对象的状态
//防止数据不一致的问题
Application["total"] = (int)Application["total"] + 1;
//尝试将Application对象中名为"total"的值(总访问量)转换为整数,然后加1,再将结果存回Applicaotn对象中
//如果"total"键不存在或不是整数,这行代码会抛出异常
Application["online"] = (int)Application["online"] + 1;
//与上面类似,尝试将Applicaont对象中名为"onLine"的值(在线人数)转换未整数,然后加1,再将结果存回Application对象中
//如果"online"键不存在或不是整数,这行代码也会抛出异常
Application.UnLock();
}
//使用Applicaotn.UnLokc()方法解除对Application对象的锁定,允许其他请求修改Application对象的状态
现在,我们已经 统计出了在线人数和历史访问数量,这连个值存储在Application对象。当需要在页面上显示这些值时,我们可以直接通过访问Applicaiton["变量名"]来获取它们。我的是在Label控件上显示人数和历史记录,我建了一个Default窗体拖拽了两个控件一个lable1和label2,用来在窗体显示历史记录和在线人数,直接将Applicaiton["onLine"]的值转换未字符串并赋值给Label的Text属性;
protected void Page_Load(object sender, EventArgs e)
{
this.lblTotal.Text = Application["total"].ToString();
//历史记录
this.lblOneLine.Text = Application["online"].ToString();
//在线人数
}
Session_End:
注意一点,因为Applicaiotn对象中存储的变量值都是Object类型的,所以当我们从Application中取出值时,我们需要确保进行正确的类型转换。如果Application["onLine"]不是一个可以转换未字符串的对象,上面的代码将会抛出异常。因此,通常我们会检查该值是否存在,并确认其类型,然后再进行转换和显示,Aapplicaiton["total"也是一样]
当一个客户端(浏览器)与服务器的会话结束时,会触发Session_End事件。在这个事件中,我们不需要修改历史访问数量,但是在线人数需要减1,以反应当前活跃的会话数量减少了。在Session_End事件中,我们可以编写如下代码来更新在线人数
void Session_End(Object sender, EventArgs e)
{
Application.Lock();
//锁定Applicaiotn对象。Lock方法确保在当前线程释放锁之前,其他线程不能修改Applicaiotn对象
//在ASP.NET中,Applicaiton对象是一个全局对象,它允许在整个Web应用程序中存储和访问数据。由于多个线程可能同时访问和修改Application对象的数据,为了避免数据不一致或竞争条件(race conditions),你要在使用它之前先锁定它。Lock方法确保了在当前线程释放锁之前,其他线程不能修改Applicaiotn对象。
Application["online"] = (int)Application["online"] - 1;
//它从Application对象中获取键为"online"的值,并假设这个值是一个整数(int)
//它将这个整数值减1,然后将结果存回Application对象中,仍然使用键"online"
//用于跟踪当前在线的用户数,每当一个会话结束时(通过Session_End事件来监测),在线用户就回减少。需要注意的是,直接进行类型转换(int)前应该检查该值是否确实存在且可以被转换为整数以避免运行时错误
Application.UnLock();
}
//解锁Application对象的。一旦你完成了对Application对象的修改,就应该立即解锁它,以便其他线程可以访问和修改它。忘记解锁Application对象可能会导致性能问题,因为其他线程将被阻塞,等待锁被释放。
Application_End:
如果服务器要关闭,历史总人数我们是不是要保存,再次登录的时候历史记录人数累加起来,所以我们就要把目前Application中存储的历史访问总数更新到数据库中,在Applicaiton_End()事件中进行:
void Application_End(Object sender, EventArgs e)
//定义一个SqlConnection对象conn,用于与数据库进行连接。连接字符串指定了数据库服务器、数据库名称、用户名和密码
{
SqlConnection con = new SqlConnection("server=.;database=countPeople;uid=sa;pwd=123;");
//这行代码创建了一个SqlConnection对象con,用于与数据库进行连接。连接字符串指定了数据库服务器、数据库名称、用户名和密码
con.Open();
//这行代码打开了数据库的连接,以便后续可以执行数据库操作
SqlCommand cmd = new SqlCommand("update countPeople set num=" + Application["total"].ToString(), con);
//创建一个SqlCommand对象cmd,用于执行sql语句, SQL语句是一个更新语句,将应用程序对象中存储"total"值更新到countPeople的num字段中
cmd.ExecuteNonQuery();
//执行了SQL更新语句,将应用程序对象存储"totle"值更新到数据库中
con.Close();
到这里大家肯定有个疑问,假如您现在是在Visual Studio 2022中,关闭系统时,并没有触发Applicaiotn_End事件,历史记录人数并没有被写到数据库。那么该如何操作才能让Application_End事件触发呢,本人找到两种方法
第一种办法:
当你运行Visual Studio 2022的时候,你的电脑右小角又会又一个IIS EXpress的图标,选中查看所有应用程序,然后停止正在运行得程序,也可以登录IIS主界面去停止程序。
第二种办法:
当应用程序域结束时,Application_End 方法会自动执行,而不需要手动触发。但是,您可以通过模拟应用程序域重新加载的方式来测试 Application_End 方法。
在代码中手动调用 HttpRuntime.UnloadAppDomain() 方法来模拟应用程序域的重新加载,从而间接地触发 Application_End 方法执行。
详细步骤:
在 ASP.NET 项目中的 Global.asax 文件。
Application_End 方法中添加这行代码
void Application_End(object sender, EventArgs e)
{
System.Diagnostics.Debug.WriteLine("应用程序结束于:" + DateTime.Now.ToString());
}
在您的代码中的某个地方,调用 HttpRuntime.UnloadAppDomain() 方法来模拟应用程序域的重新加载。我是显示历史记录和在线人数得界面上,添加了一个Button按钮
protected void Button1_Click(object sender, EventArgs e)
{
// 模拟应用程序域的重新加载
System.Web.HttpRuntime.UnloadAppDomain();
}
运行您的应用程序,并在触发了 HttpRuntime.UnloadAppDomain() 方法的位置进行操作。您将看到在应用程序重新加载时,Application_End 方法会执行,并且其中的代码逻辑将被触发。
通过以上步骤,您可以在开发和测试环境中模拟应用程序域的重新加载,从而验证 Application_End 方法的执行情况。请记住,在生产环境中要小心谨慎,避免频繁手动触发应用程序域的重新加载。
注意:只是在服务器上停止该程序的运行才会触发Application_End()事件,重启和断电等情况并不能触发。