Leistungen
Leistungen
Überblick
Leistungsangebot
Kernkompetenzen
Schulungsthemen
In-House-Schulungen
Offene .NET-Seminare
Offene WPS-Seminare
Beratung
Coaching
Support
Softwareentwicklung
Entwickler-Vermittlung
.NET/Visual Studio
TFS/ALM/Scrum
Webprogrammierung
PowerShell
Konditionen
Anfrage/Kontakt
Beratung/Coaching
Beratung/Coaching
Beratungsthemen
Coaching
Unsere Berater
Referenzkunden
Konditionen
Angebotsanfrage
In-House-Schulungen
In-House-Schulungen
Überblick
Themen/Fachgebiete
Schulungskonfigurator
Konzepte
.NET/Visual Studio
C#
VB.NET
ASP.NET
Moderne Webanwendungen
TFS/ALM/Scrum
PowerShell
Konferenzvortraege
Referenzkunden
Unsere Trainer
Konditionen
Angebotsanfrage
Offene Schulungen
Offene Schulungen
Überblick .NET-Seminare
.NET/C#-Basisseminar
WPF (Desktop)
ASP.NET/AJAX (Web)
WCF/WF (SOA)
ADO.NET/EF (Data)
Windows PowerShell
.NET, C#, VB, Visual Studio
.NET, C#, VB, Visual Studio
Startseite
Beratung/Training
Offene .NET-Seminare
Einführung
Lexikon
Artikel
Bücher
Klassenreferenz
Programmiersprachen
Entwicklerwerkzeuge
Softwarekomponenten
World Wide Wings Demo
Codebeispiele
Scripting
ASP.NET
.NET 2.0
.NET 3.0/3.5
.NET 4.0/4.5
Community
Forum
Kommerzielle Leistungen
ASP.NET
ASP.NET
Startseite
Lexikon
Sicherheit
Konfiguration
Global.asax
Tracing
Technische Beiträge
Klassenreferenz
Programmiersprachen
Entwicklerwerkzeuge
Softwarekomponenten
PowerShell
PowerShell
Überblick
Beratung
In-House-Schulungen
Öffentliche Schulungen
Codebeispiele
Commandlet Extensions
Offene PowerShell-Seminare
Inhouse-Seminare
Windows
Windows
Startseite
Windows Runtime (WinRT)
Windows PowerShell
Windows Scripting
Windows-Schulungen
Windows-Lexikon
Windows-Forum
Windows Scripting
Windows Scripting
Startseite
Lexikon
FAQ
Buecher
Architektur
Skriptsprachen
Scripting-Hosts
Scripting-Komponenten
COM/DCOM/COM+
ADSI
WMI
Scripting-Tools
WSH-Editoren
Codebeispiele
ASP.NET
.NET-Scripting
Forum
Links
Kommerzielle Leistungen
Service
Service
Website-FAQ
Anmeldung/Login
Leser-Registrierung
Gast-Registrierung
Nachrichten/RSS
Newsletter
Foren
Weblog
Lexikon
Downloads
Support
Kontakt
Site Map
Suche
Literaturtipps
Publikationen
Publikationen
Redaktionsbüro
Bücher
Fachartikel
Leser-Portal
Autoren gesucht!
Rezensionen
Über uns
Über uns
Holger Schwichtenberg
Team
Referenzkunden
Kundenaussagen
Referenzprojekte
Partner
Site Map
Suche
Weitere Websites
Tag Cloud
Impressum
Rechtliches
Datenschutzerklärung

Globale Ereignisse in ASP.NET-Webanwendungen

Die Anwendungsdatei "Global.asax" 

Die Global.asax wird generell als die (globale) Anwendungsdatei bezeichnet da sie, obwohl sie nur optional ist, eine zentrale Rolle innerhalb einer ASP.NET-Anwendung spielt. Hauptaufgabe der Global.asax-Datei ist die Definition von Ereignisbehandlungsroutinen für seitenübergreifende Ereignisse, wie zum Beispiel den Start einer Sitzung oder der gesamten Webanwendung. Eine Nebenaufgabe ist die globale Instanziierung von Objekten, die auf allen Seiten verfügbar sind.

Die Global.asax muss im Wurzelverzeichnis der Anwendung definiert werden. Wird diese Datei zur Laufzeit verändert, werden alle aktuellen Sitzungen beendet und die Webanwendung wird neu initialisiert.

Die Global.asax-Datei beginnt mit der Direktive @Application. Sie kann <OBJECT>-Tags und <SCRIPT>-Blöcke mit Ereignisbehandlungsroutinen enthalten. Der Inhalt dieser Klasse wird vom ASP.NET-Arbeitsprozess in eine Klasse umgesetzt, die von System.Web.HttpApplication erbt.

Listing 5:
Beispiel für eine global.asax-Datei (Single-File-Modell)

<%@ Application %>

 

<OBJECT RUNAT=Server SCOPE=Session ID=FSO

PROGID="Scripting.FileSystemObject">

</OBJECT>

 

<object id="ENTRY" scope="application"

class="System.DirectoryServices.DirectoryEntry"
runat="server" />

 

<script runat="Server">

 Sub Session_Start(ByVal sender As Object, ByVal e As EventArgs)

  Response.Write("Session gestartet!")

 End Sub

</script>


Die Global.asax-Datei kann auch nach dem Code-Behind-Modell implementiert werden. In diesem Fall enthält die ASAX-Datei nicht mehr als den Verweis auf die Code-Behind-Datei und –Klasse sowie die <OBJECT>-Tags. Die Ereignisbehandlungsroutinen wandern in die Global.asax.vb. Die Klasse in der Code-Behind-Datei wird von Visual Studio .NET einfach Global genannt. Andere Namen sind aber möglich.

Tabelle 3:
Grundgerüst der Implementierung der Global.asax

Global.asax

Global.asax.vb

<%@ Application

Codebehind="Global.asax.vb"

Inherits="Kapitel5.Global"

%>

Public Class Global

Inherits
  System.Web.HttpApplication


End Class

 

Hinweis

Visual Studio .NET unterstützt nur Global.asax-Dateien nach dem Code-Behind-Modell. Sie können in Visual Studio .NET nur den Quellcode der Global.asax.vb, nicht aber der Global.asax-Datei selbst bearbeiten. Dazu müssen Sie einen beliebigen Texteditor verwenden.

Globale Ereignisse

Es gibt verschiedene Arten von Ereignissen in der Global.asax-Datei. Dabei gibt es zwei Unterscheidungskritierien. Einerseits kann man die Ereignisse unterscheiden, ob sie deterministisch oder nicht deterministisch sind. Deterministische Ereignisse treten bei jeder HTTP-Anfrage bzw. der zugehörige HTTP-Antwort auf. Nicht-deterministische Ereignisse treten nur unter bestimmten Voraussetzungen, z.B. im Fehlerfall auf.

Das zweite Unterscheidungskriterium ist die Herkunft der Ereignisse. Die Global.asax-Datei bezieht Ereignisse einerseits von ihrer Oberklasse HttpApplication und andererseits aus HTTP-Modulen, die der Anwendung hinzugefügt wurden. Das folgende Listing zeigt einen Ausschnitt aus der machine.config-Datei mit den Standard-HTTP-Modulen.

Listing 6:
<httpModules> der Machine.config

<httpModules>

  <add name="OutputCache" type="System.Web.Caching.OutputCacheModule" />

  <add name="Session" type="System.Web.SessionState.SessionStateModule" />

  <add name="WindowsAuthentication" type="System.Web.Security.WindowsAuthenticationModule" />

  <add name="FormsAuthentication" type="System.Web.Security.FormsAuthenticationModule" />

  <add name="PassportAuthentication" type="System.Web.Security.PassportAuthenticationModule" />

  <add name="UrlAuthorization" type="System.Web.Security.UrlAuthorizationModule" />

  <add name="FileAuthorization" type="System.Web.Security.FileAuthorizationModule" />

</httpModules>

Ob ein Ereignis aus der Klasse HttpApplication oder einem HTTP-Modul kommt, macht insofern einen Unterschied, als dass die Ereignisse anders deklariert werden. Im ersten Fall ist der Ereignisbehandlungsroutine irrelevant; man deklariert mit dem Schlüsselwort Handles, welches Ereignis die Routine behandeln soll.

Private Sub Global_EndRequest(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.EndRequest

End Sub

Private Sub Global_Error(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Error

End Sub

Im Fall der HTTP-Modul-Ereignis, ist allein der Name wichtig.

Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs)

End Sub

Sub FormsAuthentication_OnAuthenticate(ByVal sender As Object, ByVal e As System.Web.Security.FormsAuthenticationEventArgs)

End Sub

Hinweis

Für die weitere Betrachtung soll die Herkunft der Ereignisse aber keine Rolle spielen. Wichtig ist nur zu wissen, dass durch die Installation zusätzlicher HTTP-Module auch weitere globale Ereignisse hinzukommen können.

Ereignisse aus HTTP-Modulen

Bereits im klassischen ASP gab es vier globale Anwendungs-Ereignisse:

¨          Application_OnStart()

¨          Application_OnEnd()

¨          Session_OnStart()

¨          Session_OnEnd()

Diese Ereignisse sind weiterhin vorhanden. Sie heißen jetzt aber offiziell ohne das "On" im Namen, also z.B. Session_Start() statt Session_OnStart(). Die alten Namen sind aber aus Gründen der Kompatibilität weiterhin nutzbar. Da .NET Ereignisse mit mehreren Subscribern unterstützt (sogenannte Multicast-Ereignisse), werden beide Ereignisbehandlungsroutinen ausgeführt, wenn sowohl Session_Start() als auch Session_OnStart() vorhanden ist.

Mittels dieser Ereignisse lassen sich beispielsweise Initialisierungen von Anwendungs- und Sitzungsobjekten durchführen oder Protokollierungen über die Nutzung der Anwendung durchführen.

Tipp

Wie Sie dem Listing 5 entnehmen können, kann man innerhalb der Session_Start()-Ereignisbehandlungsroutinen Ausgaben mit Response.Write() erzeugen. Dies war im klassischen ASP nicht möglich. Auch andere Ereignisse aus der global.asax unterstützen Ausgaben an den Browser.

 

Listing 7:
Allgemeine Global.asax-Ereignisse

Ereignis

Beschreibung

Application_Start()

Tritt einmalig beim Start der ASP.NET-Anwendung ein.

Application_End()

Tritt einmalig beim Beenden der ASP.NET-Anwendung ein.

Session_Start()

Bei jedem Beginn einer Benutzersitzung tritt dieses Ereignis ein.

Session_End()

Nach Beendigung einer Benutzersitzung tritt dieses Ereignis ein.

Wie diese Ereignisse verwendet werden können wird im folgenden Beispiel demonstriert. Beim Anwendungsstart (Application_Start) wird eine Zahl aus einer Textdatei gelesen. Diese beinhaltet die Anzahl über die bisherigen Starts der Anwendung. Diese wird um eins erhöht und bei beim Beenden der Anwendung (Application_End) wieder in die Datei geschrieben.

' /////////////////////////////////////////////////

' /Kapitel05c/global.asax

' /////////////////////////////////////////////////

Imports System.IO

Imports System.Web

Imports System.Web.SessionState

Public Class Global

    Inherits System.Web.HttpApplication

    Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs)

        ' Wird ausgelöst, wenn die Anwendung gestartet wird.

        Dim _StreamReader As StreamReader

        Dim _AnzahlStarts As String

        Dim _Datei As String

        _Datei = Server.MapPath("AnzahlApplicationStarts.txt")

        Try

            _StreamReader = File.OpenText(_Datei)

            _AnzahlStarts = _StreamReader.ReadLine()

        Catch exc As Exception

            ' --- Noch keine Datei vorhanden

            _AnzahlStarts = 0

        Finally

            If Not (_StreamReader Is Nothing) Then

                _StreamReader.Close()

            End If

        End Try

        Application("AnzahlApplicationStarts") = CInt(_AnzahlStarts) + 1

    End Sub

 

    Sub Session_Start(ByVal sender As Object, ByVal e As EventArgs)

        ' Wird ausgelöst, wenn die Sitzung gestartet wird.

        Application("AnzahlOffenerSessions") = Application("AnzahlOffenerSessions") + 1

        Application("AnzahlGesamtSessions") = Application("AnzahlGesamtSessions") + 1

    End Sub

 

    Sub Session_End(ByVal sender As Object, ByVal e As EventArgs)

        ' Wird ausgelöst, wenn die Sitzung beendet wird.

        Application("AnzahlOffenerSessions") = Application("AnzahlOffenerSessions") - 1

    End Sub

 

    Sub Application_End(ByVal sender As Object, ByVal e As EventArgs)

        ' Wird ausgelöst, wenn die Anwendung beendet wird.

        Dim _StreamWriter As StreamWriter

        Dim _Datei As String

        _Datei = Server.MapPath("AnzahlApplicationStarts.txt")

        Try

            ' --- Anzahl Starts in Datei schreiben

            _StreamWriter = File.CreateText(_Datei)

            _StreamWriter.WriteLine(Application("AnzahlApplicationStarts"))

        Catch exc As Exception

            ' --- Fehlerbehandlung

        Finally

            ' --- Aufräumen

            If Not (_StreamWriter Is Nothing) Then

                _StreamWriter.Close()

            End If

        End Try

    End Sub

End Class

Zusätzlich werden in diesem Beispiel alle Sessions gezählt die gerade offen sind, bzw. seit dem Start der Anwendung geöffnet wurden.

Tipp

Um das Application_Start- und Application_End-Ereignis manuell auszulösen, muss die Anwendung vollständig beendet, bzw. gestartet werden. Dies kann am leichtesten über das Beenden und Starten des WWW-Publishing-Dienstes geschehen.

Ereignisse der Klasse "HttpApplication"

Durch HttpApplication stehen Ereignisse zur Verfügung, die bei jedem einzelnen Seitenaufruf in der unten aufgeführten Reihenfolge auf. Diese können dazu verwendet werden in den Verarbeitungsprozess einer Anforderung einzugreifen, z.B. um einen Kopfzeile vor bzw. eine Fusszeile nach jeder Seite auszugeben.

 

Tabelle 4: ASP.NET-Anwendungs-Ereignisse (deterministisch)

Ereignis

Beschreibung

BeginRequest()

Kennzeichnet eine neu eingegangene Anforderung.

AuthenticateRequest()

Signalisiert dass die aktuelle Anfrage durch ein Sicherheitsmodul authentifiziert wurde.

AuthorizeRequest()

Signalisiert, dass die aktuelle Anfrage durch ein Sicherheitsmodul autorisiert wurde.

ResolveRequestCache()

Erlaubt eine Anfrage aus dem Cache. Wird vom Output Cache Modul verwendet um die Anforderung eventuell beschleunigt zu verarbeiten.

AcquireRequestState()

Signalisiert, dass eine Anforderung auf den Status der Anwendung (z.B. Sitzungsstatus) verwendet, bzw. diesen benötigt.

PreRequestHandlerExecute()

Ereignis, das vor der Ausführung des eigentlichen Anwendungsaufruf auftritt.

PostRequestHandlerExecute()

Signalisiert, dass der HTTP-Handler die Anfrage vollständig verarbeitet hat.

ReleaseRequestState()

Signalisiert, dass der Anforderungsstatus gespeichert werden soll, weil die Anwendung an dieser Stelle die Anforderung beendet.

Dieses Ereignis weißt die Status Module an die aktuellen Statusdaten zu speichern.

UpdateRequestCache()

Kennzeichnet die aktuelle Anforderung als vollständig verarbeitet und bereit für die Transferierung in den ASP.NET Cache.

EndRequest()

Signalisiert, dass die gesamte Verarbeitung beendet ist.

Diese aufgeführten Ereignisse stehen der gesamten Anwendung über die Global.asax zur Verfügung.

Beispiel

Im folgenden Beispiel wird das BeginRequest- und EndRequest-Ereignis dazu verwendet um vor und nach dem eigentlichen Generieren der Webseite zusätzliche Text auszugeben.

' ////////////////////////////////////////////////////////////////////

' /Kapitel05c/global.asax

' ////////////////////////////////////////////////////////////////////

Imports System.IO

Imports System.Web

Imports System.Web.SessionState

Public Class Global

    Inherits System.Web.HttpApplication

    Private Sub Global_BeginRequest(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.BeginRequest

        Response.Write("-- Überschrift --<br>")

    End Sub

    Private Sub Global_EndRequest(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.EndRequest

        Response.Write("-- Copyright'2002 --<br>")

    End Sub

End Class

Nicht-deterministische HttpApplication-Ereignisse

Zusätzlich gibt es HttpApplication-Ereignisse die nicht immer und nicht in einer bestimmten Phase der Anwendung auftreten. Diese Ereignisse werden in der folgenden Tabelle aufgeführt. Diese nicht-deterministischen Ereignisse treten nur unter den beschriebenen Bedingungen auf.

Tabelle 5:
nicht
deterministisch
 Anwendungs-
Ereignisse

Ereignis

Beschreibung

PreSendRequestHeaders()

Tritt vor dem Senden von HTTP-Header ein. Dadurch wird es ermöglicht, den Header zu manipulieren.

PreSendRequestContent()

Tritt kurz vor dem Senden von Daten an den Client auf.

Error()

Signalisiert eine unbehandelte Ausnahme.

Die auftretenden Ereignisse beim Aufruf einer Webseite bieten sehr viele Ansatzpunkte um eigene Verarbeitungslogik zu integrieren. Diese zusätzlichen Funktionalitäten können einerseits in der eigentlichen Global.asax-Datei oder ihrer Code-Behind-Klasse, behandelt werden.

' ////////////////////////////////////////////////////////////////////

' /Kapitel05c/global.asax

' ////////////////////////////////////////////////////////////////////

Imports System.IO

Imports System.Web

Imports System.Web.SessionState

Public Class Global

    Inherits System.Web.HttpApplication

    Private Sub Global_Error(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Error

        Dim _LetzterFehler As Exception

        _LetzterFehler = Server.GetLastError()

        Response.Write("<hr>" & _LetzterFehler.Message & "<hr>")

        Server.ClearError()

    End Sub

End Class

Dieses Beispiel behandelt aufgetretene Fehler und umgeht durch Server.ClearError() die Standard-Fehlermeldung von ASP.NET.

Statische Objekte innerhalb der Anwendung oder Sitzung

Über die Global.asax lassen sich zusätzlich Instanzen von statischen Objekten erzeugen, die von jedem Webform innerhalb der gesamten Anwendung verwendet werden können. Dadurch erhält man zentral die Möglichkeit globale Objekte zu definieren, die immer zur Verfügung stehen. Die Definition geschieht über das <OBJECT>-Tag im HTML-Code der Global.asax (nicht in der Code-Behind-Datei!), außerhalb des <SCRIPT>-Blocks.

Hinweis

Um den eigentlichen Quelltext (nicht die Code-Behind-Klasse) der Global.asax zu bearbeiten, muss man auf einen einfachen Texteditor zurückgreifen. Visual Studio .NET unterbindet diesen direkten Zugriff auf die Global.asax.

 

Abbildung 4:
Statische Objekte in der Global.asax

Diese statischen Objekte haben einen Gültigkeitsbereich (den so genannten Scope) in dem sie verwendet werden können. Dieser Scope kann sich auf eine Benutzersitzung (SCOPE="Session") oder Anwendungsweit über alle Sitzungen hinweg erstrecken (SCOPE="Application").

Um auf die entsprechenden Objekte zur Laufzeit zugreifen zu können kann die Application.StaticObjects-Liste bzw. die Session.StaticObjects-Liste verwendet werden.

' /////////////////////////////////////////////////////////

' /Kapitel05/StatischeObjekte.asp.vb

' /////////////////////////////////////////////////////////

Dim EinStatischesObjekt As DictionaryEntry

For Each EinStatischesObjekt In Application.StaticObjects

    C_ApplikationObjekte.Text += EinStatischesObjekt.Key

    C_ApplikationObjekte.Text += " - "

    C_ApplikationObjekte.Text += EinStatischesObjekt.Value.GetType.ToString()

    C_ApplikationObjekte.Text += "<br>"

Next

For Each EinStatischesObjekt In Session.StaticObjects

    C_SessionObjekte.Text += EinStatischesObjekt.Key

    C_SessionObjekte.Text += " - "

    C_SessionObjekte.Text += EinStatischesObjekt.Value.GetType.ToString()

    C_SessionObjekte.Text += "<br>"

Next

Das Resultat sieht man in der folgenden Abbildung.

Abbildung 5:
Zugriff auf statische Objekte zur Laufzeit