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()事件,重启和断电等情况并不能触发



 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/754770.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

200W-300W厚膜电阻-SOT227小方块封装功率负载电阻器

SOT-227 型电阻器是许多电流监测和精密控制应用的理想选择,其电阻值低至 0.5 mΩ。这些高度可靠的无感厚膜功率电阻器采用四端子开尔文连接,可将测量路径与电流路径隔离,当与适当的散热器一起使用时,同样适用于高功率电流监测。电…

Cookie 信息泄露 Cookie未设置http only属性 原理以及修复方法

漏洞名称:Cookie信息泄露、Cookie安全性漏洞、Cookie未设置httponly属性 漏洞描述: cookie的属性设置不当可能会造成系统用户安全隐患,Cookie信息泄露是Cookiehttp only配置缺陷引起的,在设置Cookie时,可以设置的一个…

SQLiteC/C++接口详细介绍sqlite3_stmt类简介

返回:SQLite—系列文章目录 上一篇:SQLiteC/C接口详细介绍之sqlite3类(十八) 下一篇:SQLiteC/C接口详细介绍sqlite3_stmt类(一) 预准备语句对象 typedef struct sqlite3_stmt sqlite3_stmt…

【洛谷 P9232】[蓝桥杯 2023 省 A] 更小的数 题解(字符串+区间DP)

[蓝桥杯 2023 省 A] 更小的数 题目描述 小蓝有一个长度均为 n n n 且仅由数字字符 0 ∼ 9 0 \sim 9 0∼9 组成的字符串,下标从 0 0 0 到 n − 1 n-1 n−1,你可以将其视作是一个具有 n n n 位的十进制数字 n u m num num,小蓝可以从 n…

内置泵电源,热保护电路等功能的场扫描电路D78040,偏转电流可达1.7Ap-p,可用于中小型显示器。

D78040是一款场扫描电路,偏转电流可达1.7Ap-p,可用于中小型显示器。 二 特 点 1、有内置泵电源 2、垂直输出电路 3、热保护电路 4、偏转电流可达1.7Ap-p 三 基本参数 四 应用电路图 1、应用线路 2、PIN5脚输出波形如下:

6-高维空间:机器如何面对越来越复杂的问题

声明 本文章基于哔哩哔哩付费课程《小白也能听懂的人工智能原理》。仅供学习记录、分享,严禁他用!!如有侵权,请联系删除 目录 一、知识引入 (一)二维输入数据 (二)数据特征维度 …

最细致最简单的 Arm 架构搭建 Harbor

更好的阅读体验:点这里 ( www.doubibiji.com ) ARM离线版本安装 官方提供了一个 arm 版本,但是好久都没更新了,地址:https://github.com/goharbor/harbor-arm 。 也不知道为什么不更新,我看…

数据机构-2

线性表 概念 顺序表 示例&#xff1a;创建一个存储学生信息的顺序表 表头&#xff08;Tlen总长度&#xff0c; Clen当前长度&#xff09; 函数 #include <seqlist.c> #include <stdio.h> #include <stdlib.h> #include "seqlist.h" #include &…

Auto-DataProcessing:一组让制作数据集变轻松的脚本

前言 最近跟同学参加了个比赛&#xff0c;我负责Object-Detection的技术实现&#xff0c;需要从网上扒大量的数据(主办方每种识别物就给了一张demo&#x1f923;)&#xff0c;发现数据准备是一个真的是一个非常重要但又耗时耗力的过程。对我来说&#xff0c;给我一类待识别的标…

路由器级联

目录 一、实现功能二、实现步骤2.1 接线步骤 三、效果3.1 常规连接3.2 路由器级联 一、实现功能 主路由器&#xff1a;可有WiFi功能&#xff0c;LAN口下接各设备&#xff0c;并接一个辅路由器辅路由器&#xff1a;开启WiFi功能&#xff0c;有线或无线下接各设备功能&#xff1…

IDEA直接打包Docker镜像

以下为使用IDEA打包Docker镜像并推送到远程仓库&#xff08;使用Windows打包Docker镜像并推送到远程仓库&#xff09;教程 1 安装Docker Desktop 下载地址&#xff1a;https://www.docker.com/products/docker-desktop/ 安装成功后&#xff0c;可在cmd查看版本号 2 启动Do…

qt开发记录

文章目录 1、QT介绍2、信号和槽机制3、提升类4、播放媒体5、增加新的组件6、联合vscode开发 1、QT介绍 打开的主页面介绍&#xff0c;下面是一张新的工程的QT编辑栏&#xff0c;我这里大致分为三类&#xff0c;分别标注如下&#xff1a; 下面对这三个进行分别说明&#xff1a…

leetcode刷题(javaScript)——动态规划相关场景题总结

动态规划在 JavaScript 刷题中有一定的难度&#xff0c;但也是非常常见和重要的算法思想。动态规划通常适用于需要求解最优解、最大值、最小值等问题的场景&#xff0c;可以将复杂问题拆分成子问题&#xff0c;通过存储子问题的解来避免重复计算&#xff0c;从而提高效率。 理解…

v3-admin-vite 整合pont

需求 目前后端的Admin模板使用的是v3-admin-vite&#xff0c;需要整合pont接口&#xff0c;方便前后端统一一体化开发 安装PONT 按照官方的文档&#xff0c;将pont engine安装好&#xff0c;然后在项目根目录执行pont start。注意生成代码路径要修改一下&#xff0c;因为v3-a…

AGI之Humanoid Robot:Figure 01的介绍、核心技术、功能、应用案例之详细攻略

AGI之Humanoid Robot&#xff1a;Figure 01的介绍、核心技术、功能、应用案例之详细攻略 目录 Figure 01的介绍 1、特点 2、应用场景 Figure 01的主要功能 Figure 01的应用案例 1、传递苹果 2、搬箱子 3、拿盘子 Figure 01的介绍 2024年3月13日&#xff0c;Figure 01是…

带你深入了解数据库的事务

为什么要使用事务 日常开发中&#xff0c;很多操作&#xff0c;不是通过一个SQL就能完成的&#xff0c;往往需要多个SQL配合完成 当执行多个SQL操作的时候&#xff0c;如果中间出现了特殊的情况&#xff08;程序崩溃&#xff0c;系统奔溃&#xff0c;网络断开&#xff0c;主机…

java数据结构与算法刷题-----LeetCode1005. K 次取反后最大化的数组和(这就不是简单题)

java数据结构与算法刷题目录&#xff08;剑指Offer、LeetCode、ACM&#xff09;-----主目录-----持续更新(进不去说明我没写完)&#xff1a;https://blog.csdn.net/grd_java/article/details/123063846 卷来卷去&#xff0c;把简单题都卷成中等题了 文章目录 1. 排序后从小到大…

Spring Boot 实现程序的优雅退出

&#x1f3f7;️个人主页&#xff1a;牵着猫散步的鼠鼠 &#x1f3f7;️系列专栏&#xff1a;Java全栈-专栏 &#x1f3f7;️个人学习笔记&#xff0c;若有缺误&#xff0c;欢迎评论区指正 目录 前言 优雅停机是什么 SpringBoot如何实现优雅停机 合理杀死进程 法一&…

SQLiteC/C++接口详细介绍之sqlite3类(十八)

返回目录&#xff1a;SQLite—免费开源数据库系列文章目录 上一篇&#xff1a;SQLiteC/C接口详细介绍之sqlite3类&#xff08;十七&#xff09; 下一篇&#xff1a;SQLiteC/C接口详细介绍sqlite3_stmt类&#xff08;一&#xff09; ​ 56.sqlite3_update_hook 函数功能&am…

C++面试宝典第36题:骑士游历

题目 在国际象棋的棋盘上,使一个骑士遍历所有的格子一遍且仅一遍。对于任意给定的顶点,输出一条符合上述要求的路径。骑士的走法和中国象棋的马的走法一样,走日。 解析 本题是一个经典的回溯搜索问题,具体来说是求解国际象棋棋盘上骑士的遍历问题,也称为骑士巡游问题(Kni…