Lấy thông tin chi tiết từ người dùng viếng thăm website của bạn
Đã bao giờ bạn muốn xem những ai đang duyệt website của bạn vào một thời
điểm thực không? Họ có bao nhiêu người? Họ sử dụng trình duyệt gì? Họ từ
đâu đến? Địa chỉ host và tên host của họ là gì? Và chính xác trang nào mà họ
đang đọc. Tất cả một cách thật chi tiết, nếu bạn muốn như thế thì article này
chính là dành cho bạn.
Chúng ta sẽ học gì trong article này?
Những chủ đề dưới đây sẽ được đề cập:
• Làm thế nào để đếm số người đang duyệt website?
• Làm thế nào để đếm tất cả số người dùng truy cập vào website kể từ khi ứng
dụng web được bắt đầu?
• Làm thế nào để biết thời điểm cuối cùng mà ứng dụng khởi động lại?
• Làm thế nào để giữ được thông tin mỗi người dùng trên site?
Chúng ta làm gì trong article này?
Chúng ta sẽ tạo và chỉnh sửa bốn file sau đây:
• viewSessions/default.aspx (file ASP.NET)
• viewSessions/UserInfo.cs (file C#)
• Global.asax (file ứng dụng ASP.NET)
• viewSessions/compiled.bat
Để biên dịch file nguồn thongtinUser.cs, chúng ta sẽ tạo một file .bat (batch).
Một khi đã biên dịch, chúng ta sẽ có một file Stardeveloper.Test1.dll trong thư
mục bin.
Đây là screenshot khi chạy ứng dụng trên local host, và xem trang
viewSessions/default.aspx
Global.asax
Bắt đầu bằng việc tạo ra file “Global.asax” . Đây là file chính cho ứng dụng
của chúng ta nhưng nó sẽ không hiển thị đối với người dùng cuối. Global.asax
là một file chứa sự kiện ứng dụng (application event) cho các trang ASP.NET
gần giống với Global.asa trong các trang ASP. File này chứa các application
event mà bạn có thể override để sử dụng cho chính bạn.
Global.asax chứa các event nhiều hơn file gốc Global.asa. Nếu bạn là một
người mới, và bạn không biết application event là gì, thì application event là
những hành động xảy ra trong một ứng dụng web, như khi ứng dụng bắt đầu,
khi ứng dụng kết thúc, khi nhận được một request, khi một response được tạo
ra… Những gì chúng ta có thể làm là đặt một vài đoạn mã cho những event đó
nếu chúng ta muốn sử dụng chúng. Ví dụ như nếu chúng ta muốn ghi lại thời
gian ứng dụng của chúng ta bắt đầu, chúng ta cần sử dụng event “bắt đầu ứng
dụng”.
Ứng dụng xem session của chúng ta sử dụng những event sau đây:
• Application_OnStart: gọi khi ứng dụng được bắt đầu
• Session_OnStart: gọi khi session của một user mới được bắt đầu
• Session_OnEnd: gọi khi session của một user tồn tại kết thúc hoặc chương
trình thoát một cách tự động
• Application_OnPostRequestHandlerExecute: gọi khi request được xử lý bởi
Request Handler và HttpSessionState có sẵn.
Tạo hoặc chỉnh sửa file “Global.asax” và chắc chắn rằng nó chứa các dòng mã
dưới đây cho bốn application event. Nếu bạn đã có sẵn mã cho các event này
trong file Global.asax của bạn, thì bạn chỉ cần chỉnh sửa lại các method event
cho đúng với đoạn mã của chúng ta.
<%@ Import namespace="Stardeveloper.Test" %>
<%@ Application Debug="true" %>
<script language="C#" runat="server">
public void Application_OnStart(Object sender, EventArgs e) {
Hashtable ht = (Hashtable)Application["SESSION_LIST"];
if(ht == null) {
ht = new Hashtable();
lock(Application) {
Application["SESSION_LIST"] = ht;
Application["APP_START_TIME"] = DateTime.Now;
Application["TOTAL_SESSIONS"] = 0;
}
}
}
public void Session_OnStart(Object sender, EventArgs e) {
UserInfo ui = new UserInfo();
Session["USER_INFO_MAP"] = ui;
Hashtable ht = (Hashtable)Application["SESSION_LIST"];
if(ht.ContainsKey(Session.SessionID) == false) {
ht.Add(Session.SessionID, Session);
}
lock(Application)
{
int i = (int)Application["TOTAL_SESSIONS"];
i++;
Application["TOTAL_SESSIONS"] = i;
}
}
public void Session_OnEnd(Object sender, EventArgs e) {
Session.Clear();
Hashtable ht = (Hashtable)Application["SESSION_LIST"];
ht.Remove(Session.SessionID);
}
public void Application_OnPostRequestHandlerExecute(Object sender,
EventArgs e) {
try {
UserInfo ui = (UserInfo)Session["USER_INFO_MAP"];
if(ui != null && Session.IsNewSession) {
try {
if(Request.UrlReferrer != null) {
ui.URLReferrer = Request.UrlReferrer.ToString();
}
ui.UserAgent = Request.UserAgent;
ui.HostAddress = Request.UserHostAddress;
ui.HostName = Request.UserHostName;
}
catch (Exception) {
}
}
if(ui != null) {
ui.URLViews.Add(Request.RawUrl);
}
}
catch(Exception) {
}
}
</script>
Giải thích
<%@ Import namespace = “Stardeverloper.Test” %>
Dòng đầu tiên là một phát biểu bổ sung trực tiếp namespace
“Stardeverloper.Test”. Chúng ta làm điều này để bổ sung lớp UserInfo sẽ được
tạo ra sau này trong article.
<%@ Application Debug = “true” %>
Đây là một ứng dụng trực tiếp, và chúng ta sử dụng nó để ấn định thuộc tính
“Debug” là “true”. Điều này có nghĩa là nếu có một vài đoạn mã bị sai, và trình
biên dịch không thể biên dịch đoạn mã này thì bạn sẽ được xem chính xác
dòng mã nào gây ra lỗi đó.
<script language = “C#” runat = “server”> … </script>
Tất cả mã cho Global.asax sẽ được đặt trong thẻ <script> và </script>. Thuộc
tính “language” sẽ xác định ngôn ngữ bạn sẽ viết mã giữa những thẻ này, trong
trường hợp của chúng ta là C#. Thuộc tính “runat” phải là “server” bởi vì đoạn
mã của chúng ta sẽ chạy trên server.
Phần này giải thích cụ thể về đoạn mã trong Global.asax và trong file
UserInfo.cs
public void Application_OnStart(Object sender, EventArgs e) {
Hashtable ht = (Hashtable)Application["SESSION_LIST"];
if(ht == null) {
ht = new Hashtable();
lock(Application) {
Application["SESSION_LIST"] = ht;
Application["APP_START_TIME"] = DateTime.Now;
Application["TOTAL_SESSIONS"] = 0;
}
}
}
Trong Application_OnStart, đầu tiên chúng ta nhìn vào đối tượng
System.Collections.Hashtable tồn tại trong đối tượng Application. Như bạn đã
biết, đối tượng Application được cung cấp cho toàn bộ các file ASP.NET và
thay thế cho toàn bộ ứng dụng. Nó rất hữu dụng và chứa những thông tin cụ
thể về ứng dụng. Ở đây chúng ta sử dụng nó để lưu trữ và nhận những đối
tượng của chúng ta mà chúng ta muốn giữa các request và các session của
người dùng. Nếu Hashtable đó không được tìm thấy thì chúng ta tạo ra một cái
Hashtable mới và lưu nó vào trong đối tượng Application sử dụng khóa
“SESSION_LIST”. Để biết khi nào ứng dụng của chúng ta bắt đầu, chúng ta
lưu lại ngày tháng hiện tại sử dụng khóa “APP_START_TIME”. Đối tượng
cuối cùng mà chúng ta lưu là một số nguyên thay thế tổng số người dùng duyệt
website kể từ khi ứng dụng được khởi động lại. Thông tin này được lưu trong
khóa “TOTAL_SESSIONS”
public void Session_OnStart(Object sender, EventArgs e) {
UserInfo ui = new UserInfo();
Session["USER_INFO_MAP"] = ui;
Hashtable ht = (Hashtable)Application["SESSION_LIST"];
if(ht.ContainsKey(Session.SessionID) == false) {
ht.Add(Session.SessionID, Session);
}
lock(Application) {
int i = (int)Application["TOTAL_SESSIONS"];
i++;
Application["TOTAL_SESSIONS"] = i;
}
}
Kế tiếp, chúng ta viết mã cho sự kiện Session_OnStart. Đầu tiên chúng ta tạo
ra một đối tượng Stardeveloper.Test.UserInfo. Đối tượng này sẽ được tạo cho
mỗi session và sẽ chứa thông tin về mỗi session cụ thể như tên host, địa chỉ
host, URL mà người dụng đang xem…
Sau đó chúng ta lưu đối tượng UserInfo vào đối tượng Session sử dụng khóa
“USER_INFO_MAP”. Đối tượng Session làm việc gần giống như đối tượng
Application khi nó cũng lưu và nhận vào các đối tượng. Nhưng Session chỉ
chứa những đối tượng cho vòng đời của một session, trong khi Application chỉ
chứa những đối tượng cho vòng đời của một ứng dụng.
Kế tiếp chúng ta nhận vào mã Hashtable mà chúng ta đã lưu trước đó trong đối
tượng Application và giả sử rằng nó không chứa một Session mới này, chúng
ta sẽ thêm vào Session đang tồn tại này vào trong Hashtable của ứng dụng.
Điều này cho phép chúng ta lưu lại tất cả những đối tượng Session của người
dùng trong đối tượng Hastable. Và tại sao chúng ta làm điều này? Đó là vì để
nhận được tất cà các session hiện tại và hiển thị thông tin của chúng.
Tiếp đó, chúng ta khóa đối tượng Application (để ngăn nó bị chỉnh sửa bởi
nhiều thread vào cùng một thời điểm) và tăng biến đếm “TOTAL_SESSIONS”
public void Session_OnEnd(Object sender, EventArgs e) { Session.Clear();
Hashtable ht = (Hashtable)Application["SESSION_LIST"];
ht.Remove(Session.SessionID);
}
Không có nhiều mã trong event Session_OnEnd, đơn giản chúng ta chỉ xóa đi
Session (xóa tất cả các đối tượng trong nó) và xóa Session này trong danh sách
các Session đang hoạt động của đối tượng Application.
public void Application_OnPostRequestHandlerExecute(Object sender,
EventArgs e) { try {
UserInfo ui = (UserInfo)Session["USER_INFO_MAP"];
if(ui != null && Session.IsNewSession) {
try {
if(Request.UrlReferrer != null) {
ui.URLReferrer = Request.UrlReferrer.ToString();
}
ui.UserAgent = Request.UserAgent;
ui.HostAddress = Request.UserHostAddress;
ui.HostName = Request.UserHostName;
}
catch (Exception) {
}
}
if(ui != null) {
ui.URLViews.Add(Request.RawUrl);
}
}
catch(Exception) {
}
}
Event cuối cùng là Application_OnPostRequestHandlerExecute. Ở đây, chúng
ta nhận đối tượng UserInfo từ Session và giả sử rằng đó là lần đầu tiên người
dùng truy cập vào bất kỳ trang nào trong website của chúng ta. (chúng ta làm
điều này bằng cách sử dụng thuộc tính Session.IsNewSession). Chúng ta sẽ
chuyển cho đối tượng UserInfo những giá trị khác nhau nhận được từ đối
tượng Request. Nếu đối tượng Session này không phải mới, thì chúng ta chỉ
thêm URLvào danh sách các URL đã được xem trong Session của đối tượng
UserInfo cụ thể.
UserInfo.cs
Chúng tạo ra lớp UserInfo của chúng ta mà chúng ta đã nói ở phần trên. Chúng
ta đặt mã nguồn trong thư mục viewSessions.
Tạo một file UserInfo.cs và copy/paste đoạn mã dưới đây.
using System;
using System.Collections;
namespace Stardeveloper.Test {
public class UserInfo {
private ArrayList urlViews;
private string userAgent;
private string urlReferrer;
private string hostAddress;
private string hostName;
public UserInfo() {
this.urlViews = new ArrayList();
}
public ArrayList URLViews {
get { return this.urlViews; }
set { this.urlViews = value; }
}
public string UserAgent {
get { return this.userAgent; }
set { this.userAgent = value; }
}
public string URLReferrer {
get { return this.urlReferrer; }
set { this.urlReferrer = value; }
}
public string HostAddress {
get { return this.hostAddress; }
set { this.hostAddress = value; }
}
public string HostName {
get { return this.hostName; }
set { this.hostName = value; }
}
}
}
Không có nhiều mã trong lớp này, (nó tương tự với những gì một lớp JavaBean
có). Chúng ta đang sử dụng nó để lưu một giá trị cụ thể cho một Session.
using System; using System.Collections;
Sử dụng phát biểu “using” nói cho trình biên dịch biết những namespace nào
chúng ta sẽ sử dụng trong đoạn mã
namespace Stardeveloper.Test { public class UserInfo {
Khi chúng ta công bố namespace mà lớp UserInfo thuộc về và bắt đầu đoạn mã
cho lớp của chúng ta.
private ArrayList urlViews;
private string userAgent;
private string urlReferrer;
private string hostAddress;
private string hostName;
Các giá trị của UserInfo sẽ được giữ lại
public UserInfo() {
this.urlViews = new ArrayList();
}
Đoạn mã khởi tạo một ArrayList “urlViews” cho lớp UserInfo của chúng ta.
Sau đó là viết mã cho 5 thuộc tính của lớp UserInfo
Phần này trình bày về file default.aspx là phần chính để hiển thị thông tin trong
application
Default.aspx
Giờ đã đến lúc viết mã cho trang default.aspx. Trang này sẽ hiển thị thông tin
về tất cả người dùng từ những đối tượng đã được lưu trong các đối tượng đã
lưu trong Application và Session
<%@ Page language="C#" AutoEventWireup="true" Debug="true" %>
<%@ Import namespace="Stardeveloper.Test" %>
<script runat="server">
public void Page_Load(object sender, System.EventArgs e) {
Hashtable ht = (Hashtable)Application["SESSION_LIST"];
IDictionaryEnumerator en = ht.GetEnumerator();
StringBuilder sb = new StringBuilder();
sb.Append("<table width=\"100%\" align=\"center\" border=\"1\"");
sb.Append(" bordercolor=\"silver\"");
sb.Append("cellpadding=\"2\"><tr style=\"background-
color:#CCDDEE;\"><td>");
sb.Append("Current Sessions</td><td>Total Sessions Since Reboot</td>");
sb.Append("<td>Application Reboot Time</td></tr>");
sb.Append("<tr><td>").Append(ht.Count).Append("</td><td>");
sb.Append(Application["TOTAL_SESSIONS"]).Append("</td><td>");
sb.Append(Application["APP_START_TIME"].ToString().Replace('/', '-'));
sb.Append("</td></tr>");
sb.Append("</table>");
sb.Append("<p align=\"center\">Active Sessions</p>");
while(en.MoveNext()) {
HttpSessionState session = (HttpSessionState)en.Value;
if(session != null) {
UserInfo user = (UserInfo)session["USER_INFO_MAP"];
string urlReferrer = user.URLReferrer;
string hostAddress = user.HostAddress;
string hostName = user.HostName;
string userAgent = user.UserAgent;
if(urlReferrer == null) {
urlReferrer = "Bookmark";
}
if(hostAddress == null) {
hostAddress = " ";
}
if(hostName == null) {
hostName = " ";
}
if(userAgent == null) {
userAgent = " ";
}
sb.Append("<table width=\"100%\" align=\"center\" border=\"1\"");
sb.Append(" bordercolor=\"silver\"");
sb.Append("cellpadding=\"2\"><tr
style=\"background-color:#CCDDEE;\"><td>");
sb.Append("SessionID</td>");
sb.Append("<td>Host
Address</td><td>Host Name</td>");
sb.Append("<td>Page View Count</td></tr>");
sb.Append("<tr><td>").Append(session.SessionID.ToUpper());
sb.Append("</td><td>");
sb.Append(hostAddress).Append("</td><td>");
sb.Append(hostName).Append("</td><td>");
sb.Append(user.URLViews.Count).Append("</td></tr>");
sb.Append("<tr
style=\"background-color:#CCDDEE;\"><td colspan=\"2\">");
sb.Append("URL Referrer</td>");
sb.Append("<td colspan=\"2\">User
Browser</td></tr><tr><td colspan=\"2\">");
sb.Append(urlReferrer).Append("</td><td
colspan=\"2\">").Append(userAgent);
sb.Append("</td></tr>");
sb.Append("<tr
style=\"background-color:#CCDDEE;\"><td colspan=\"4\">");
sb.Append("Pages
Viewed</td></tr><tr><td colspan=\"4\">");
if(user.URLViews.Count > 0) {
int i = 1;
foreach(string url in user.URLViews) {
sb.Append(i).Append(". ");
sb.Append(url).Append("<br>");
i++;
}
}
else {
sb.Append(" ");
}
sb.Append("</td></tr></table><br>");
}
}
this.label.Text = sb.ToString();
}
</script>
<html>
<head>
<style>
body, td { font-family: Tahoma,Verdana; font-size:8pt; }
td { padding-left: 5; }
</style>
</head>
<body>
<asp:Label id="label" runat="server" />
</body>
</html>
Giải thích
Tất cả đoạn mã của chúng ta đặt trong method PageLoad sẽ tạo ra mỗi khi
trang ASP.NET được tải.
Hashtable ht = (Hashtable)Application["SESSION_LIST"];
IDictionaryEnumerator en = ht.GetEnumerator();
Chúng ta nhận đối tượng được lưu trong Hastable từ đối tượng Application sử
dụng khóa “SESSION_LIST”. Tiếp đó chúng ta nhận một đối tượng
IdictionaryEnumerator từ Hastable này. Chúng ta làm điều này bởi vì chúng ta
muốn tương tác thông qua các đối tượng mà Hastable của chúng ta chứa và
IdictionaryEnumerator cung cấp cho ta chức năng này.
StringBuilder sb = new StringBuilder();
Chúng ta tạo một đối tượng StringBuilder cục bộ để xây dựng một chuỗi text
từ nhiều đối tượng chuỗi nhỏ. Chúng ta tạo ra đối tượng StringBuilder bằng
việc sử dụng lớp StringBuilder ra lớp sẽ có lợi hơn là kết chuỗi đơn giản bằng
toán tử “+”. Tạo ra bảng hiển thị thông tin về những người dùng hoạt động
hiện thời. Đếm tất cả người dùng khi ứng dụng khởi động lại và thời gian ứng
dụng khởi động lại.