Viewers Vieleicht ist dem ein oder anderen der Besucherzähler in der oberen rechten Ecke meines Blog aufgefallen der anzeigt, wie viele Besucher gerade den Blog ansehen. Genauer gesagt werden hier die aktiven Sitzungen, oder Sessions, gezählt. Wenn eine neue Session gestartet wird erhöht sich der Zähler, wird eine Sitzung beendet wird der Zähler um eins verringert. Das ist sehr einfach in der Global.asax der jeweiligen Anwendung zu realisieren. Allerdings müssen ein paar Voraussetzungen erfüllt sein:
Sitzungsdaten müssen verwendet werden und der Wert mode in der Konfigurationsgruppe SessionState muss auf den Wert InProc der SessionStateMode-Enumeration eingestellt werden. Sollten also die Sitzungsdaten in einem Session- oder SQL Server gespeichert werden, ist dieser Ansatz unbrauchbar. Schon daher ist ersichtlich, dass sich so eine Lösung nur für kleine ASP.NET Anwendungen eignet.

Sind die Voraussetzungen erfüllt, ist die Implementierung sehr einfach. Zunächst einmal muss in der aktuellen Anwendung ein Objekt erzeugt werden, welches die Anzahl der Betrachter hält. In der Methode Application-Start in der Datei Global.asax wird lediglich ein Schlüssel Wert Paar erzeugt. Den Schlüssel habe ich Viewers genannt.

void Application_Start(object sender, EventArgs e)
{
    // Schlüssel Viewers in der Anwendung erzeugen
    Application["Viewers"] = 0;

}

Wenn die Anwendung jetzt startet, wird der Schlüssel in der Anwendung erzeugt und enthält den Wert 0. Um den Wert auf einer Seite darzustellen, wird noch ein Element benötigt. Ich habe mich hier für ein Benutzersteuerelement entschieden, das lediglich ein Literal verwendet um die Daten darzustellen.

<%@ Control Language="C#" AutoEventWireup="true"
     CodeFile="Viewers.ascx.cs"
     Inherits="themes_klaus_b_Viewers" %>
<asp:Literal ID="Literal1" runat="server"></asp:Literal>

Im Codebehind des UserControl wird lediglich der Inhalt des Literal geschrieben. Natürlich könnten hier auch Inline Tags verwendet werden, doch ich stehe auf Codebehind.

using System;
using System.Web.UI;

public partial class themes_klaus_b_Viewers : UserControl
{
    protected void Page_Load(object sender, EventArgs e)
    {
        this.Literal1.Text = Application["Viewers"].ToString() +           " Besucher online";
    }
}

Bis jetzt wird allerdings noch nichts gezählt. Um den Besucherzähler, der ja eigentlich nur Sitzungen zählt, zu erhöhen verwenden wir die Methode Session_Start der Global.asax die bei jeder neu gestarteten Session von der Anwendung ausgelöst wird. Da aber theoretisch gleichzeitig von verschiedenen Aufrufern der Seite eine neue Sitzung angefordert werden kann, bietet ASP.NET die Methode Lock um Zugriffe auf den Anwendungsstatus zu synchronisieren. Natürlich muss die gesperrte Anwendung nach dem erhöhen des Zählers mit UnLock wieder frei gegeben werden.

void Session_Start(object sender, EventArgs e)
{
    // User-Zähler erhöhen.
    Application.Lock();
    Application["Viewers"] = (int)Application["Viewers"] + 1;
    Application.UnLock();
}

Genauso verhält es sich wenn eine Sitzung beendet wird.

void Session_End(object sender, EventArgs e)
{
    // User-Zähler verringern.
    Application.Lock();
    if ((int)Application["Viewers"] > 0)
    {
        Application["Viewers"] = (int)Application["Viewers"] - 1;
    }
    Application.UnLock();
}

Bis jetzt wurde alles Serverseitige erledigt. Das schließen oder beenden des Browsers bekommen wir aber nicht mit. Um auch das schließen eine Browserfenster mitzubekommen, ist ein wenig clientseitige Arbeit, oder JavaScript, nötig. Dazu muss lediglich in einem JavaScript das Window.BeforeUnload Ereignis verwendet werden. Wenn das Ereignis eintritt, wird auf dem Client ein XHTML Objekt erzeugt, welches via GET eine aspx-Seite anfordert die wiederum die aktuelle Sitzung mit Session.Abandon beendet. Da ich eine MasterPage verwende, lasse ich das JavaScript im Codebehind in der OnInit Methode mit einem StringBuilder erzeugen und anschließend registrieren. In Zeile 12 muss natürlich der korrekte Pfad zur AbandonSession.aspx angegeben werden.

protected override void OnInit(EventArgs e)
{
    // prüfen ob abandonScript bereits registriert ist
    if (!this.Page.ClientScript.         IsClientScriptBlockRegistered("abandonSession"))
    {
        // Script zum Aufruf von AbandonSession.aspx
        StringBuilder sb = new StringBuilder();
        sb.Append("function window.onbeforeunload(){");
        sb.Append("if(event.clientX > document.body.clientWidth && event.clientY < 0){");
        sb.Append("var xmlhttp = new ActiveXObject(\"Microsoft.XMLHTTP\");");
        sb.Append("xmlhttp.open(\"GET\", \"");
        sb.Append(VirtualPathUtility.ToAbsolute("~/") + "themes/klaus_b/AbandonSession.aspx");
        sb.Append("\", false);");
        sb.Append("xmlhttp.send();}");
        sb.Append("}");

        // Script Registrieren
        this.Page.ClientScript.RegisterClientScriptBlock(
              this.GetType(),
              "abandonSession",
              sb.ToString(),
              true);
    }

    // für Uplevel Browser markieren
    this.Page.ClientTarget = "uplevel";

    // Initialisieren
    base.OnInit(e);
}

Jetzt wird nur noch die Seite AbandonSession.aspx benötigt. Diese Seite muss keinen Inhalt haben. Lediglich im Page_Load Ereignis wird die aktuelle Session, wie schon weiter oben angesprochen, beendet.

using System;
using System.Web.UI;

public partial class themes_klaus_b_AbandonSession : Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        // aktuelle Sitzung beenden
        Session.Abandon();
    }
}

Jetzt ist der Besucherzähler soweit einsatzbereit. Dabei ist folgendes zu bedenken:
Die vorgestellte Variante ist keinesfalls ein präziser Zähler, da allein das ActiveXObject AFAIK nicht von allen Browsern unterstützt wird. Auch die Sicherheitseinstellungen mancher Benutzer können hier keine sauberer Zählung gewährleisten.
Es soll ja auch keine Webseiten-Statistik erstellen, sondern ist lediglich ein nettes Gimmick. Für exakte Zählungen gibt es schließlich professionelle Dienste.

Technorati-Tags:  |  | 
Wenn ihnen der Artikel gefallen hat oder er für sie hilfreich war, bitte "kicken" sie ihn.
kick it on dotnet-kicks.de