In this article I’ll explain some simple ways to create your own web statistics that tracks visits and information about visitors. Why do we need to do this? If your ISV doesn’t provides the statistics or if it is expensive for you or all you have is a simple counter, you won’t be able to track any information about visits or your visitors. Some counters just aggregate visits, and you get only total number of hits, but you don’t know which pages are accessed.
That’s why I created two examples. First and simplest example is Counter that efficiently can replace the counter your ISV provides if it doesn’t suit you. Second and a little bit complex example is more than just a counter. It can track every single visit and provide you with the details such as time of visit, which resource was requested, where your visitor came from, which browser the visitor used and so on. When you have all the information about visits stored in one place, it’s easy to get various reports.
Simple Web Counter
The goal is simple. Lets store the number of visits for each accessed resource. It could be aspx page or some zip archive. The scenario is sipmle: We’ll catch the current request and save the requested URL. For each Url we’ll kepp the total number of visits. If it is the first time the URL is accessed it will be added to the end of the list, and visit counter set to one. In other case, visit counter for the URL wil be incremented by one.
We’ll keep the data in XML file in bot examples. You can use the database, tekst file, comma-separated file, or whatever you chose. Our XML log file has this structure:
<?xml version="1.0" encoding="utf-8"?>
<pages>
<Page Url="/Counter/Default.aspx" Visits="1" />
</pages>
We’ll have StatsManager class that will manage visit tracking. It exposes SaveStats method that accepts URL and manage it in the scenario described above. The code belows implements this scenario.
public void SaveStats(string url)
{
XmlDocument xmldoc = new XmlDocument();
xmldoc.Load(HttpContext.Current.Server.MapPath("~/stats.xml"));
XmlNodeList nodeList = xmldoc.GetElementsByTagName("Page");
bool urlExists = false;
foreach (XmlNode x in nodeList)
{
if (x.Attributes["Url"].Value == url)
{
urlExists = true;
int visits = Convert.ToInt32(x.Attributes["Visits"].Value) + 1;
x.Attributes["Visits"].Value = visits.ToString();
}
}
if (!urlExists)
{
XmlElement newElement = xmldoc.CreateElement("Page");
newElement.SetAttribute("Url", url);
newElement.SetAttribute("Visits", "1");
xmldoc.DocumentElement.AppendChild(newElement);
}
xmldoc.Save(HttpContext.Current.Server.MapPath("~/stats.xml"));
}
It is really simple and I won’t go deep into it. It uses basic XML operations, and if you are interested more in XML manipulation, check out this article on GotDotNet samples.
All we need to do now is to catch the Request in order to extract the URL fromit. We can do it in Application_BeginRequest handler in Global.asax or by using HttpModule. In order to keep this simple, we’ll use the Global.asax class.
void Application_BeginRequest(object sender, EventArgs e)
{
StatsManager manager = new StatsManager();
manager.SaveStats(Request.Url.PathAndQuery);
}
This is all we have to do to make this code functional. Please note that we do not filter the request url here and that means that any resource that comes with aspx page will pe proccessed. You will have to implement your own logic here . It can log only aspx pages, and/or zip archivec, pdf files, or just images form a specific folder... It’s up to your logic and the requirements.
This example allow us to track simple information, but we still don’t have enought details about visits. For example, we can’t track the number of hits month to month and taht could be a valuable information. We can see where the visitors are coming from – is it Google or some other search engine, and so on. That why we’ll extend the previous example.
More complex statistics
Main logic will remain in this example. We’ll catch the Requst in Application_BeginRequest and pass it to StatsManager.
void Application_BeginRequest(object sender, EventArgs e)
{
StatsManager manager = new StatsManager();
manager.SaveStats(Request);
}
As you can see in the code above, we’ll pass the entire Request to the StatsManager in order to extract as much details as we need.
XML log file will be different and will looke like the sample below:
<?xml version="1.0" encoding="utf-8"?>
<visits>
<Page
TimeStamp="1/3/2008 10:45:18 PM"
Url="http://localhost:2608/Statistics/Page1.aspx"
UrlReferrer="http://localhost:2608/Statistics/Page1.aspx"
Browser="IE"
BrowserType="IE7"
BrowserVersion="7.0"
Platform="WinXP"
UserHostName="127.0.0.1"
UserHostAddress="127.0.0.1" />
</visits>
According to this structure, SaveStats method in StatsManager will look like this:
public void SaveStats(HttpRequest request)
{
XmlDocument xmldoc = new XmlDocument();
xmldoc.Load(HttpContext.Current.Server.MapPath("~/stats.xml"));
XmlNodeList nodeList = xmldoc.GetElementsByTagName("Visit");
XmlElement newElement = xmldoc.CreateElement("Page");
newElement.SetAttribute("TimeStamp", DateTime.Now.ToString());
newElement.SetAttribute("Url", request.Url.ToString());
if (request.UrlReferrer != null)
newElement.SetAttribute("UrlReferrer",
request.UrlReferrer.ToString());
else
newElement.SetAttribute("UrlReferrer", "");
newElement.SetAttribute("Browser", request.Browser.Browser);
newElement.SetAttribute("BrowserType", request.Browser.Type);
newElement.SetAttribute("BrowserVersion", request.Browser.Version);
newElement.SetAttribute("Platform", request.Browser.Platform);
newElement.SetAttribute("UserHostName", request.UserHostName);
newElement.SetAttribute("UserHostAddress", request.UserHostAddress);
xmldoc.DocumentElement.AppendChild(newElement);
xmldoc.Save(HttpContext.Current.Server.MapPath("~/stats.xml"));
}
In this example, in contrast to previous example, the information is always appending. Each new request is added as a new record in XML log file. We track the date and time of visit, requested URL, URL that precede (URLReferrer), browser details, user host address and name. You can log whatever data you want, and whatever is available through the Request class. More information obout the Request class can be found on MSDN Articles.
It is clear now that this data allow us to find out much more about visits and visitors. We can create weekly, monthly or yearly statistics, or we can review the visits stats for a specific page or file. Based on UrlReferrer we can see, for example how many visitors came from Google ot Yahoo search engines. We can also see which browsers our visitors use, and so on. Like I mentioned before, I’ll leave the creation of reports to you.
Conclusion
By reading this article you read how we can implement simple web statistics in an easy way. This can be very good solution for your existing applications, because you don’t have to change your code, but rathar just add StatsManager class, XML log file and Global.asax (unless you alredy have one – in that case you’ll just need to extend Application_BeginRequest handler. Please note that both examples serve just as an idea that you should extend and adjust according to your needs.
What’s for end?
- The data in XML file will grow and after a while you should archive records, and clear old records. You can do it on month or year basis. If visitis grow enoughtm I recommend you to pay for a professional service or find some free but good enough. The only free service I found on the Interner that looks like it is worth is StatCounter (http://www.statcounter.com/).
- If you ar an enthusiast, you can implement even more complex statistics. Wayne Plourde wrote a good articl, and you can read it here: http://www.15seconds.com/issue/021119.htm. I dislike the architecture in the example, but it can be treated just as an idea. The solution he made tracks behaviour of each visitor using Session_Start and Session_End handlers in Global.asaxand by using cookies. That allows you to see which pages are accessed by some visitor, how long didi he stayed on each page and so on.
- Download both examples in the ZIP archive.