北大青鸟的视频中讲了很多很实用的例子,这是其中一个,在实现的过程中,遇到一些问题,但也都在老师的指导下和通过查阅资料解决了,感觉收获颇丰。
在做这个例子的时候发现:ASP.NET的Application和Session统计在线人数和历史访问人数时不准。明明已经关闭浏览器了,在线人数却没少,重新登录,历史人数也没增加。难道是我做错了,No.原因在这里。
首先,先简单说一下Application和Session。
Application:应用程序类的对象。类比到这个程序,服务器端的统计人数程序就相当于一个Application,而用户与之建立的连接则相当于一个Session。
由此,能理解到:Application是共享的,相当于全局变量,Session则是会话级的,相当私有变量。
借用师哥的一张图代表他们的关系就是:
类比出:
当程序启动时,首先执行Application_Start()事件:这里有两个两个变量:total用于记录历史人数,online用于记录在线人数。
<span style="font-family:KaiTi_GB2312;font-size:24px;"> protected void Application_Start(object sender, EventArgs e) { SqlConnection con = new SqlConnection("server=.;database=countPeople;uid=sa;pwd=123456;"); con.Open(); SqlCommand cmd = new SqlCommand("select * from countPeople", con); int count = Convert.ToInt32(cmd.ExecuteScalar()); con.Close(); Application["total"] = count; Application["online"] = 0; }</span>
继而,当用户登录时,会触发Session_Start()事件。让两变量+1。这里还加了一个锁,是为了防止并发访问而导致错误。加锁后:Application的Lock()方法先把Application中的变量锁起来(Application执行了Lock()方法之后,整站中所有关于Application的操作都会被锁定延时执行,包括Application赋值和Application读取),只让一个客户端进行这两个变量的自增,之后再进行解锁,供其他客户端进行操作:
<span style="font-family:KaiTi_GB2312;font-size:24px;"> protected void Session_Start(object sender, EventArgs e)//进行连接 { Session.Timeout = 1; Application.Lock();//加锁:防并发 Application["total"] = (int)Application["total"] + 1; //历史人数+1 Application ["online"]=(int)Application ["online"]+1; //在线人数+1 Application .UnLock();//解锁 }</span>至此,历史人数和在线人数都更新在变量中了,需要的时候调用即可。
当一个客户端下线的时候,会触发Session_End()事件,这时,在线人数-1。
<span style="font-family:KaiTi_GB2312;font-size:24px;"> protected void Session_End(object sender, EventArgs e)//断开连接 { Application.Lock(); Application["online"] = (int)Application["online"] - 1; Application.UnLock(); }</span>做过这个例子的同学应该遇到过:打开两个客户端,即建立两个Session,在线人数为2,关闭其中一个,刷新另一个,结果在线人数还是2。
最后,关闭程序,Application中存储的历史访问数据存入数据库。
<span style="font-family:KaiTi_GB2312;font-size:24px;"> protected void Application_End(object sender, EventArgs e) { SqlConnection con = new SqlConnection("server=.;database=countPeople;uid=sa;pwd=123456;"); con.Open(); SqlCommand cmd = new SqlCommand("update countPeople set num="+Application["total"].ToString(),con); cmd.ExecuteNonQuery(); con.Close(); }</span>但结束运行后,会发现,数据库中并没有增加的数据,这说明关闭系统时没有触发Application_End()这个事件。那该怎么做呢?
首先,得把程序发布,以IIS为例:当想触发Application_End()时,需要在IIS中关闭此程序的运行。重启和强行关闭都不会触发该事件。
除此方法可以触发Application_End()外,正常关机可以触发,正常关机时,Web应用程序关闭,历史记录更新。而Web关闭时,关的是:控制面板\系统和安全\管理工具\服务:world wide web publishing service,所以,为了开着机看效果,我们可以手动关闭该项,以此来更新数据库。
总结:
这是一个很实用的例子,今后应该会经常遇到。通过这个例子,了解了Application和Session的区别,联系......也通过这个例子,学会了不断尝试,再尝试中寻找并验证答案......