این مقاله به شرح این مطلب میپردازد که چگونه صفحات وب asp.net را ردگیری کنیم بدون آنکه نیازی به ابزارهای جانبی داشته باشیم.البته این بدان معنی نیست که به کل از همه ابزارهای جانبی بینیاز خواهیم شد اما خواهیم توانست ابزار مورد نیاز خود را بسیازیم و مطابق با نیازهای کاری خود آن را توسعه دهیم.
تعیین مکان
بعنوان یک برنامه نویس وب، مسلما برای ما مهم است که بازدید کنندگان ما در کجا قرار دارند.این مورد همچنین برای بسیاری از بخشهای کاری نیز یک ضرورت است.
مقاله های متعددی در سایتهای مختلفی وجود دارد که مکان بازدید کنندگان را با توجه به آدرس IP آنها اعلام میکند. همچنین وب سرویسهای متعددی نیز در این زمینه نوشته شده است. ما در اینجا از geobytes.com استفاده میکنیم. شیوه استفاده از این سایت بدین شکل است:
<html>
<body>
<script language="Javascript"
src="http://gd.geobytes.com/Gd?after=-
1&variables=GeobytesCountry,GeobytesCity,GeobytesRegion">
</script>
<script language="javascript">
if(typeof(sGeobytesCountry) != "undefined" &&
typeof(sGeobytesRegion) != "undefined" &&
typeof(sGeobytesCity) != "undefined")
{
var url = 'index.aspx?IPCity='+sGeobytesCity+'&IPRegion='+
sGeobytesRegion+'&IPCountry='+sGeobytesCountry;
document.write("<META HTTP-EQUIV='Refresh' CONTENT='0; URL="+url+"'>");
} else
{
document.write("<META HTTP-EQUIV='Refresh' CONTENT='0; URL=index.aspx'>");
}
</script>
</body>
</html>
با استفاده از کد بالا، یک سفر به سایت GeoBytes خواهیم داشت و در پایان شهر، منطقه و کشور بر اساس آدرس IP کاربر را بدست خواهیم آورد.پس از این، صفحه آغازین ASPX خود را فراخوانی خواهیم کرد و به آن صفحه، این 3 پارامتر را به صورت query string ارسال خواهیم نمود.
اکنون اطلاعات مورد نظر را داریم و میتوانیم از آنها برای تحلیل داده ها یا فرستادن کاربران به صفحات مخصوص خود استفاده کنیم.
در اینجا ما سعی کرده ایم از
این مقاله
که توسط Wayne Plourde نوشته شده است استفاده کرده و آن را ارتقا دهیم. مقاله مذکور این اعمال را انام میدهد:
• یک نمونه از کلاس Tracker ایجاد کرده و آنرا درون session قرار میدهد
• از کوکی ها برای ذخیره سازی مقادیر قبلی متغیرهایی که علاقمند به ردگیری آنها بودیم استفاده میکند
• هر زمان که کاربر صفحه ای را بازدید کند، شیء tracker موجود در session را به روز میکند
• اطلاعات را زمانی که رخدادهای session_start و session_end رخ میدهند منتشر میکند
• زمانی که session انقضا می یابد، آمار صفحات بازدید شده را منتشر میکند.
تغییراتی که ما داده ایم به این شرح هستند:
• زمانی که session انقضا می یابد، رخداد session_end شبیه سازی میشود
• شیء tracker به جای آنکه در session قرار گیرد، در یک جدول hash قرار داده میشود.
نکته دیگر این که در این مثال سعی کرده ایم به جای بهره گیری از فایل global.asax و رخدادهای آن، از HTTPModule بهره بگیریم.دلایل این کار نیز چنین است که نیازی به داشتن چند فایل global.asax برای چند پروژه نداشته باشیم و برای همه پروژه ها ازتنظیمات یکسان استفاده کنیم.
در این پروژه، از کلاسی به نام EADFramework استفاده کرده ایم. برای ثبت HTTPModule مورد نظرمان در میبایست فایل web.confog را ویرایش کرده و پارامترهای لازم را نیز مقدار دهی کنیم
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="MailFrom" value="mailto:yourMailFrom@yourserver.com">yourMailFrom@yourserver.com" />
<add key="MailTo" value="mailto:yourMailTo@yourserver.com">yourMailTo@yourserver.com" />
<add key="SmtpServer" value="smtp.yourmailserver.com" />
<add key="SiteTracking" value="Full" />
<add key="ExcludeIPList" value="127.0.0.1,10.,192.168,172.16" />
</appSettings>
<system.web>
<httpModules>
<add name="EADHttpModule"
type="EAD.Controller.EADHttpModule, EADFramework" />
</httpModules>
<compilation defaultLanguage="c#" debug="true" />
<trace enabled="false" requestLimit="10" pageOutput="false"
traceMode="SortByTime" localOnly="true" />
<sessionState mode="StateServer"
stateConnectionString="tcpip=127.0.0.1:42424" timeout="20" />
</system.web>
</configuration>
شما میتوانید ردگیری صفحات را توسط تنطیم مقادیر Full یا None برای SiteTracking فعال یا غیرفعال کنید.همچنین میتوانید از ExcludeIPList برای فیلتر کردن آدرس های IP محلی یا شبکه داخلی خود استفاده کنید.ضمن آنکه میتوانید از IncludeIPList برای نظارت روی یک یا چند آدرس IP بخصوص استفاده نمایید.
HttpModule تعریف رخدادها برای
ما نیاز به این داریم که 3 رخداد را در HttpModule خود برای ردگیری صفحات ثبت کنیم
Register Events: public void Init(HttpApplication app)
{
app.BeginRequest += (new EventHandler(this.OnBeginRequest));
app.PreRequestHandlerExecute +=
(new EventHandler(this.OnPreRequestHandlerExecute));
if (app.Modules["Session"] != null)
{
SessionStateModule session = (SessionStateModule)
app.Modules["Session"];
app.AcquireRequestState +=
(new EventHandler(this.OnAcquireRequestState));
session.Start += (new EventHandler(this.OnSessionStart));
}
}
رخداد AcquireRequestState زمانی رخ میدهد که asp.net وضعیت session جاری را که به درخواست فعلی اختصاص یافته است بدست آورد. این مکانی است ایده آل برای ایجاد یک شیء کش با یک تابع callback
private void OnAcquireRequestState(Object source, EventArgs ea)
{
HttpApplication app = (HttpApplication)source;
HttpContext ctx = (HttpContext) app.Context;
ctx.Cache.Add(key,ctx.Session.SessionID,null,
DateTime.Now.AddMinutes(ctx.Session.Timeout),TimeSpan.Zero,
CacheItemPriority.Normal,onCacheRemove);
string key = ctx.Session.SessionID;
CacheItemRemovedCallback onCacheRemove = null;
try
{
ctx.Cache.Remove(key);
onCacheRemove = new CacheItemRemovedCallback
(this.CacheRemoveCallback);
}
catch(Exception exception)
{
string message = exception.Message;
// Publish Exception
}
}
متد CacheRemoveCallBack متد PageTrackerUtil.TrackSessionEnd را برای انتشار آمار در انتهایsession فراخوانی میکند. متد CacheCallBackMethod نیز زمانی که session انقضا میابد اجرا خواهد شد.
private void CacheRemoveCallback(string key, Object source,
CacheItemRemovedReason reason)
{
if (reason == CacheItemRemovedReason.Expired)
{
PageTrackerUtil.TrackSessionEnd(key);
}
}
از SessionStateModule برای ثبت رخداد OnSessionStart استفاده میکنیم.از این رخداد زمانی استفاده میکنیم که شخصی به سایت دسترسی پیدا کرده و بخواهیم آن را اطلاع دهیم.
private void OnSessionStart(Object source, EventArgs ea)
{
PageTrackerUtil.TrackSessionStart(HttpContext.Current);
}
رخداد PreRequestHandlerExecute تنها یک لحظه قبل از اینکه asp.net آغاز به اجرای یک صفحه کند استفاده میکنیم. از این رخداد برای نظارت بر صفحات به صورت انفرادی استفاده میکنیم.
private void OnPreRequestHandlerExecute(object source, EventArgs e)
{
PageTrackerUtil.TrackSessionPages(((HttpApplication)source).Context);
}
متدهای ردیابی صفحه
از طریق HttpModule که قبلا شرح داده شد، ما میتوانیم با 3 متد TrackSessionStart, TrackSessionPages و TrackSessionEnd سر و کار داریم تا ردیابی در سطح صفحه را کنترل کنیم. از آنجایی که ما به Session در زمانی که توسط asp.net منهدم میشود دسترسی نداریم، ما از جدول hash ساده و کوچک خودمان برای ذخیره سازی اشیاء برای ردیابی در سطح صفحه استفاده میکنیم
private static void UpdateSessionConst(string key, PageTracker tracker)
{
if (SessionConst.Session[key] == null)
{
SessionConst.Session.Add(key,tracker);
}
else
{
SessionConst.Session.Remove(key);
SessionConst.Session.Add(key,tracker);
}
}
public static void TrackSessionStart(HttpContext ctx)
{
string key = ctx.Session.SessionID;
string siteTracking =
ConfigurationSettings.AppSettings["SiteTracking"];
string ip = ctx.Request.UserHostAddress.ToString();
if (siteTracking == null || siteTracking.Length == 0) return;
if (siteTracking.ToLower() != "none" && ValidTracking(ctx))
{
PageTracker tracker = new PageTracker(ctx);
UpdateSessionConst(key,tracker);
EADUtility.SendMail(tracker.SessionUserHostAddress,
CreateTrackerMessageBody(tracker));
}
}
در آغاز یک session، ما از کلاس PageTracker یک شیء میسازیم و آن را در جدول hash خودمان در SessionConst.Session ذخیره میکنیم
using System;
using System.Collections;
namespace EAD.Constant
{
public class SessionConst
{
public static Hashtable Session = new Hashtable();
public static Hashtable Page = new Hashtable();
}
}
TrackSessionPages
public static void TrackSessionPages(HttpContext ctx)
{
string siteTracking =
ConfigurationSettings.AppSettings["SiteTracking"];
if (siteTracking == null || siteTracking.Length == 0 ||
siteTracking.ToLower() == "none") return;
if (ctx.Session == null) return;
string key = ctx.Session.SessionID;
siteTracking = siteTracking.ToLower();
if (siteTracking == "full" || siteTracking == "partial")
{
if (SessionConst.Session[key] != null)
{
PageTracker tracker = (PageTracker) SessionConst.Session[key];
if (tracker != null)
{
string relativeFilePath = ctx.Request.Url.AbsolutePath.Remove(0,
ctx.Request.ApplicationPath.Length).ToLower();
// Remove things after ? mark.
int pos = relativeFilePath.IndexOf("?");
if (pos > 0)
{
relativeFilePath = relativeFilePath.Substring(0,pos);
}
if (siteTracking == "full")
{
tracker.AddPage(relativeFilePath);
}
else if (PageVisit(relativeFilePath))
{
tracker.AddPage(relativeFilePath);
}
UpdateSessionConst(key,tracker);
}
}
}
در ردگیری در سطح صفحه، ما PageTracker را از جدول hash ایستای صفحه بازیابی میکنیم و پس از آنکه اطلاعات ردیابی در سطح صفحه را به آن اضافه کردیم، آن را در SessionConst.Session ذخیره میکنیم.
public static void TrackSessionEnd(string key)
{
string siteTracking = ConfigurationSettings.AppSettings["SiteTracking"];
if (siteTracking == null || siteTracking.Length == 0) return;
if (siteTracking.ToLower() != "none")
{
if (SessionConst.Session[key] != null)
{
PageTracker tracker = (PageTracker) SessionConst.Session[key];
SessionConst.Session.Remove(key);
SessionConst.Page.Remove(key);
if (tracker != null)
{
EADUtility.SendMail(tracker.SessionUserHostAddress+"-End",
CreateTrackerMessageBody(tracker)+
CreateTrackerPageListing(tracker));
}
}
}
}
کلاس Page Tracker
تا بحال، تنها از روالهای مدیریتی سیستم ( administrative ) برای ردیابی در سطح صفحه استفاده میکردیم. ذکر این نکته لازم است که اطلاعات واقعی در سطح صفحه در کلاس PageTracker ذخیره میشوند.
مقداردهی اولیه پارامترها در متد سازنده کلاس PageTracker انجام میگیرد.
public PageTracker(HttpContext ctx)
{
string KEY = ctx.Session.SessionID;
pages = new ArrayList();
expires = DateTime.Now.AddYears(1);
sessionReferrer = (ctx.Request.UrlReferrer == null) ?
string.Empty : ctx.Request.UrlReferrer.ToString();
sessionURL = (ctx.Request.Url == null) ? string.Empty :
ctx.Request.Url.ToString();
if (SessionConst.Page[KEY] == null)
{
visitCount = 1;
originalReferrer = sessionReferrer;
originalURL = sessionURL;
SessionConst.Page.Add(KEY,new PageHashData(visitCount,
sessionReferrer,sessionURL));
}
else
{
PageHashData pageHashData = (PageHashData) SessionConst.Page[KEY];
pageHashData.PageCount++;
SessionConst.Page.Remove(KEY);
SessionConst.Page.Add(KEY,pageHashData);
visitCount = ((PageHashData)SessionConst.Page[KEY]).PageCount;
originalReferrer = ((PageHashData)SessionConst.Page[KEY]).Referrer;
originalURL = ((PageHashData)SessionConst.Page[KEY]).Url;
}
userHostAddress = ctx.Request.UserHostAddress.ToString();
userAgent = ctx.Request.UserAgent.ToString();
browser = ctx.Request.Browser.Browser;
crawler = ctx.Request.Browser.Crawler.ToString();
}
متد AddPage باعث فراخوانی متد TrackSessionPages شده است.
public void AddPage(string pageName)
{
PageData pti = new PageData();
pti.PageName = pageName;
pti.Time = DateTime.Now;
pages.Add(pti);
}
استفاده از کوکی ها برای ذخیره اطلاعات نیز حذف شده است و به جای آن از کلاسهای PageHashData و PagaData که در جدول hash صفحه در SessionConst ذخیره میشوند، استفاده میشود.
using System;
namespace EAD.Utility
{
[Serializable]
public class PageHashData
{
private string referrer, url;
private int pageCount;
public PageHashData(int pageCount, string referrer, string url)
{
this.pageCount = pageCount;
this.referrer = referrer;
this.url = url;
}
public int PageCount { get { return pageCount;}
set{pageCount = value;} }
public string Referrer{ get { return referrer;} }
public string Url{ get { return url;} }
}
}
using System;
namespace EAD.Utility
{
[Serializable]
public class PageData
{
public string PageName;
public DateTime Time;
}
}