Net Web Services Architecture and Implementation Compress
Net Web Services Architecture and Implementation Compress
ASP.NET-
Programmierung mit VB.NET
Sandini Bib
programmer’s choice
Die Wahl für professionelle Programmierer und Softwareentwickler. Aner-
kannte Experten wie z. B. Bjarne Stroustrup, der Erfinder von C++, liefern
umfassendes Fachwissen zu allen wichtigen Programmiersprachen und den
neuesten Technologien, aber auch Tipps aus der Praxis.
Die Reihe von Profis für Profis!
ASP.NET-
Programmierung
mit VB.NET
Dynamische, datenbankgestützte Webseiten
mit .NET entwickeln
Alle Rechte vorbehalten, auch die der fotomechanischen Wiedergabe und der
Speicherung in elektronischen Medien.
Die gewerbliche Nutzung der in diesem Produkt gezeigten Modelle und Arbeiten
ist nicht zulässig.
Fast alle Hardware- und Softwarebezeichnungen, die in diesem Buch erwähnt werden,
sind gleichzeitig eingetragene Produktbezeichnungen oder sollten als solche betrachtet werden.
Umwelthinweis:
Dieses Produkt wurde auf chlorfrei gebleichtem Papier gedruckt.
5 4 3 2 1
05 04 03
ISBN 3-8273-1975-7
Inhalt
Vorwort 13
12 Servererweiterungen 1027
12.1 Schnellstart 1027
12.1.1 ber dieses Kapitel 1027
12.2 HTTP-Handler 1028
12.2.1 Vorhandene HTTP-Handler 1028
12.2.2 Erweiterung durch eigene Handler 1030
12.2.3 Programmierung eines eigenen Handlers 1031
12.2.4 HTTP-Handler ohne IIS-Konfiguration verwenden 1037
12.3 HTTP-Module 1037
12.3.1 Grunds>tzliche Funktionsweise 1038
12.3.2 Anwendungsbeispiel 1039
13 Webservices 1043
13.1 Schnellstart 1043
13.1.1 ber dieses Kapitel 1043
13.2 Grundlagen 1044
13.2.1 Die Protokolle 1045
13.3 Webservices konsumieren 1054
13.3.1 Hinweise zu Cffentlichen Diensten 1054
13.3.2 Ein einfaches Programm am Beispiel Google 1055
13.3.3 WSDL programmtechnisch auswerten 1064
13.4 Webservices anbieten 1076
13.4.1 Anregungen f"r den praktischen Einsatz 1076
13.4.2 Praktische Umsetzung eines Dienstes 1077
D Anhang 1085
Index 1091
Sandini Bib
Vorwort
Sie haben vermutlich bereits einiges "ber .NET gehCrt und gehC-
ren damit zu einem erlauchten Kreis. Wenn Sie dieses Buch gele-
sen haben, werden Sie ASP.NET – eine der derzeit fortschrittlichs-
ten Technologien zur Webserverprogrammierung – kennen und
damit zu einem noch erlauchteren Kreis gehCren.
Wer bislang mit Java und JSP gek>mpft hat, dem d"rfte der Ein-
stieg in ASP.NET dagegen nicht nur leichter fallen, sondern auch
eine Art Offenbarung darstellen. Denn hier ist vieles nicht nur ein-
facher, sondern auch schneller zu erledigen. Umsteiger von ASP
werden mehr zu k>mpfen haben, denn sie steigen nun in die Welt
der professionellen Softwareentwickler ein. Hier sind Themen wie
Objektorientierung, Debugging, Tracing, Designer usw. bestim-
mend. Dennoch ist mit VB.NET eine recht brauchbare Implemen-
tierung gelungen. Diese orientiert sich aber naturgem>ß weit
mehr an VB 6 als an VBScript. Der Anspruch ist klar: Mit .NET
kann Software in besserer Qualit>t und dennoch in k"rzerer Zeit
entwickelt werden. Dem Entwickler, der lediglich das Problem
Sandini Bib
14 Vorwort
Sie sollten sich auch einige Regeln zurecht legen, um effektiv ler-
nen zu kCnnen. Hier ein paar Tipps:
In diesem Sinne kann sich der Leser freuen. Das erworbene Wis-
sen qualifiziert auch f"r andere Aufgaben. Der Fokus dieses Bu-
ches liegt auch auf der Vermittlung der Sprache VB.NET. Trotz
der Phnlichkeit im Namen sind die Unterschiede zu VBScript sig-
nifikant und zu VB 6 immer noch erheblich. Auch hier ist also eine
Lernkurve zu bew>ltigen. Daf"r kann man auch außerhalb von
ASP.NET mit VB.NET professionelle Software schreiben. Insofern
ist es mehr als nur ein einfaches Lernbuch, denn es sollte ein ganz-
heitlicher Ansatz vermittelt werden. Die begrenzte Seitenzahl ei-
nes Buches zwang dennoch zu einer ausschnittsweisen Darstel-
lung. Seitenlange Tabellen, die denen in der Referenz
entsprechen, wurden vermieden. Ebenso sind Ihnen endlose Wie-
derholungen derselben Funktionen in immer neuen Varianten er-
spart geblieben. Vieles erschließt sich ohnehin nur, wenn man die
Zusammenh>nge verstanden hat. Die Vermittlung der Hinter-
Sandini Bib
Inhalt 15
gr"nde, egal ob es solche aus der .NET-Welt sind oder nicht, stand
dann auch im Mittelpunkt der Bem"hungen der Autoren.
Ob die Methodik erfolgreich war, kCnnen Sie gern direkt den Au-
toren mitteilen. Wir freuen uns "ber jede R"ckmeldung. Ebenso
stehen wir gern zur Verf"gung, wenn es um die Ausbildung von
Mitarbeitern oder die Umsetzung von Projekten geht. Schreiben
Sie an folgende E-Mail-Adresse: [email protected].
Die Teile
Das Buch ist in drei Teile und einen Anhang gegliedert. Die drei
Teile trennen den Inhalt nach dem Niveau:
Die zweite Maßnahme zur Leitung des Lesers sind Einf"hrungen Einfhrungen
in die Kapitel. Diese Abschnitte tragen immer den Titel »ber die-
ses Kapitel«. Darin ist nicht nur eine Vorschau auf den Inhalt ent-
halten, sondern auch eine sehr kompakte Zusammenfassung, ein
grober berblick "ber das Thema. Sie kCnnen von hier gezielt in
die einzelnen Abschnitte springen, da zu allen Haupt"berschrif-
ten entsprechende Links eingebaut wurden.
Nicht zuletzt hat es sich in der Praxis als sehr wichtig heraus- Referenzverweis
gestellt, immer Zugriff auf die Online-Referenz oder die MSDN-
Library zu haben. Es ist nat"rlich schwer, darin etwas zu finden,
wenn man den Namen der Dinge nicht kennt, nach denen man
sucht. Deshalb steht vor jedem Kapitel ein Abschnitt mit dem Titel
»Wegweiser in die Referenz«, der die verwendeten Klassen, Me-
thoden oder Kommandos in ihrem Kontext darstellt und kurze
Hinweise zur Benennung gibt. Diese Darstellungen erheben kei-
nen Anspruch auf Vollst>ndigkeit, bieten aber durchaus beste Hil-
fe bei der Suche.
Beispiele
In der Wissensvermittlung war »Learning-by-Doing« schon im-
mer einer der erfolgreichsten Wege. Damit Sie alles ausprobieren
Sandini Bib
20 ber das Buch
ASP.NET erlaubt die Trennung von Code und Design. In fast al-
len F>llen, wo diese Technik verwendet wird, stimmen die Namen
von Design- und Code-Datei "berein. Die folgenden beiden Lis-
tings gehCren zusammen:
<html>
</html>
Listing 2: Eine sinnlose Datei (SinnLos.aspx)
Sandini Bib
Hinweise zur Schreibweise und Symbolik 21
Imports SinnLos
Sub Page_Load ()
' nichts
End Sub
Listing 3: Sinnloser Code dazu (SinnLos.aspx.vb)
Wenn Sie Profi werden wollen und ein solides Basiswissen be-
nCtigen, helfen Ihnen die Exkurse dabei, einen Blick "ber den
Tellerrand zu werfen.
Schreibweise
Im Buch wird zur Hervorhebung spezieller WCrter eine einheitli-
che Schreibweise verwendet:
brigens: Nur das, was im Text als »Listing« bezeichnet wird und
mit einer Listingunterschrift versehen ist, finden Sie auf der CD
und im Web und kCnnen es meist ohne weiteres ausf"hren. Alle
anderen Codes dienen nur der Erl>uterung oder Erg>nzung und
sind nicht allein ausf"hrbar. Beachten Sie aber immer die Hinwei-
se im Text, manche Listing bed"rfen der Anpassung an die Ver-
Sandini Bib
ber das Buch 23
Symbole
Damit Sie z"gig mit dem Buch arbeiten kCnnen, werden in aller
K"rze die Techniken gezeigt, die Sie vorfinden. Wichtige Elemen-
te sind durch Symbole gekennzeichnet:
Tipp – Dieses Symbol kennzeichnet Passagen, die aus dem Kontext he-
rausragen, Zusatzinformationen liefern oder einfach interessant sind. t
Hinweis – Besonderheiten und abweichendes Verhalten in bestimmten
Situationen wird mit dem Hinweis-Symbol gekennzeichnet.
Die Buch-CD
Die CD zum Buch enth>lt folgende Daten:
Wenn Sie Visual Studio .NET nicht verwenden, kopieren Sie die einzel-
t nen aspx- und aspx.vb-Dateien von der CD und verwenden Sie diese
direkt. Beachten Sie die stellenweise ben5tigten Spieldaten in diversen
Unterverzeichnissen.
Die Projekte umfassen jeweils ein oder mehrere Kapitel. Alle ent-
haltenen Programme sind exakt so benannt, wie im Buch in den
jeweiligen Listing-Unterschriften. Die Zuordnung zwischen den
Projektnamen und den Kapiteln des Buches kCnnen Sie der fol-
genden Tabelle entnehmen:
Tabelle 1: Namen der Projekte und der Kapitel, aus denen sie Programme enthalten
Installation Bevor Sie die Programme von der CD installieren, m"ssen Sie
"ber ein lauff>higes Framework und ASP.NET verf"gen. Visual
Studio .NET ist in vielen F>llen empfehlenswert, aber nicht zwin-
gend erforderlich. Die Programme zu diesem Buch liegen in Form
eines Installationsprogramms vor. Um sie verwenden zu kCnnen,
gehen Sie folgendermaßen vor:
http://localhost/AspnetVBNet/index.htm
Wenn Sie Ihren Webserver nicht lokal betreiben, ersetzen Sie »lo-
calhost« durch den entsprechenden Namen oder die IP-Adresse.
Wichtig ist, dass Sie die URL verwenden und nicht den Aufruf
"ber das Dateisystem. Der Steuerung der Listen der Programme
erfolgt "ber ein kleines ASP.NET-Programm, das nur ausgef"hrt
wird, wenn der IIS die Seite verarbeitet.
Nach der Installation kCnnen Sie aus den gelieferten Dateien die Projekte in Visual
Projekte in Visual Studio .NET rekonstruieren. Der hier beschrie- Studio .NET
wiederherstellen
bene Weg sichert ab, dass die Programme alle mit lokalen Pfaden
angesprochen werden, so als ob Sie diese selbst erstellt h>tten. Ge-
hen Sie dazu folgendermaßen vor:
1. Legen Sie eine neue Projektmappe an. Speichern Sie diese in ei-
nem lokalen Ordner.
2. F"gen Sie der Projektmappe nun Projekte hinzu. Verwenden
Sie dazu die Option Projekt vom Web ffnen. Suchen Sie die
Projekte in dem Ordner, den Sie bei der Installation angegeben
haben.
3. Stellen Sie die Konfiguration Ihrer Projekte auf Debug ein.
4. Erstellen Sie die gesamte Projektmappe erneut – rechte Maus-
taste auf die Projektmappe zum Aufruf des Kontextmen"s
und dann Projektmappe erstellen w>hlen.
5. Jetzt kCnnen Sie einzelne Programme mit (F5) oder (Strg-F5)
starten. Beachten Sie dabei, dass diese Tasten – mit oder ohne
Debugger – immer das so genannte Startprojekt und darin die
Startdatei starten. Beides l>sst sich "ber die Kontextmen"s der
Projekte bzw. Dateien einrichten. Alternativ kCnnen Sie die
Programme weiter "ber die Startdatei der Applikation,
index.htm, erreichen. Vergessen Sie nicht, die Programme nach
Pnderungen neu zu erstellen.
Sandini Bib
26 ber das Buch
Probleme? Informieren Sie die Autoren bitte, wenn Sie glauben Programm-
fehler gefunden zu haben oder es Schwierigkeiten mit der Instal-
lation gibt. Auf der Webseite zum Buch finden Sie einige Zeit nach
Erscheinen des Buches Updates der Installationsprogramme.
Sie finden dort – fr"hestens vier Wochen nach Erscheinen des Bu-
ches – eine aktualisierte Fassung der gesamten Projektmappe vor.
Hostingservice
Wenn Sie einen Provider suchen, der Ihre Applikation aufnimmt,
ohne dass Sie gleich einen eigenen Server aufsetzen, kCnnen wir
Ihnen die Firma QualityHosting empfehlen. Mehr Informationen
dazu finden Sie im Web unter http://www.qualityhosting.de.
A Vorbereitung auf
ASP.NET
Sandini Bib
Sandini Bib
Die Programmiersprachen
Erste Unterschiede werden bereits mit der Wahl der Program-
miersprache offensichtlich. ASP wird "berwiegend mit VBScript
programmiert, alternativ wird auch JScript verwendet. Das offene
Konzept des Scripting Host erlaubt dabei auch andere Sprachen,
wie beispielsweise Perl und Python. Diese konnten sich in der
ASP-Welt bislang kaum durchsetzen, weil die eigenen Bibliothe-
ken zur Webserverprogrammierung umfangreicher sind als die
mit ASP gelieferten. ASP-Programme kCnnen von der Erweiter-
Sandini Bib
30 1 Prinzip und Funktionsweise
barkeit "ber COM bzw. COM+ profitieren – wenn Sie denn in der
Lage sind, mit C++ oder Visual Basic nativ zu programmieren.
Fnf Program- Mit .NET ist diese Unterscheidung nicht mehr gegeben. Sie erstel-
miersprachen len Programme in VB.NET, C#, JScript.NET, J# oder C++.NET
verfgbar
und nicht mehr in einer Skriptsprache. C++.NET r"ckt dabei et-
was in den Hintergrund, denn die bersetzung in die IL (Inter-
mediate Language) erlaubt nur noch wenige sprachtypische Vor-
teile, sodass es nur selten lohnt, aus Laufzeitgr"nden die Sprache
zu wechseln. Verf"gbar ist auch ein Java-Dialekt, aus lizenzrecht-
lichen Gr"nden J# genannt. Wer vorher Java programmiert hat,
wird sich hier zu Hause f"hlen. Allerdings erstellt der J#-Com-
piler keinen Code, der von einer Java Virtual Machine ausgef"hrt
werden kann, sondern wie alle .NET-Sprachen IL-Code.
In diesem Buch wird VB.NET verwendet. Wenn Sie sich f"r C# in-
teressieren, finden Sie eine Version dieses Buches mit C# unter
der ISBN 3-8273-1974-9.
Sandini Bib
Unterschiede zum alten ASP 31
Abarbeitung
Ein wesentlicher technologischer Unterschied zwischen ASP und Interpreter vs.
ASP.NET ist die Art der internen Code-Verarbeitung. W>hrend Compiler
Dateierweiterungen
Wie bei ASP wird eine Webseite "ber den IIS ausgeliefert und die .aspx anstelle .asp
Verarbeitung erfolgt aufgrund einer Verkn"pfung zwischen einer
bestimmten Dateierweiterung und der ASP.NET-Komponente.
Aus .asp ist dabei, unter anderem, .aspx geworden. »Unter ande-
rem« deshalb, weil es noch andere Dateierweiterungen gibt, die
bestimmte Sonderdienste in ASP.NET ansprechen.
Modularisierung
ASP kennt selbst keine Modularisierungskonzepte. Lediglich die
SSI (Server Side Includes), die "ber den IIS verf"gbar sind, kCnnen
eingesetzt werden, um Dateien mit Codeteilen wiederzuverwen-
den. SSI sind mit ASP.NET "brigens nicht verschwunden, solche
Zeilen wie <!– #include file="name.htm" –> funktionieren nach wie
vor. Der Unterschied besteht darin, dass Sie eine F"lle von elegan-
teren und leistungsf>higeren Modularisierungsfunktionen haben,
die SSI schnell in Vergessenheit geraten lassen.
Kunden-Steuer- Noch weiter gehen die Kunden-Steuerelemente. Hier wird eine ei-
elemente gene Designvorschrift entworfen und Code dazu geschrieben.
Dieser wird dann einzeln in eine Assembly "bersetzt. Das Verfah-
ren ist nicht nur erstaunlich einfach, sondern auch sehr leistungs-
f>hig. Sie kCnnen Code n>mlich so gut sch"tzen und geben nur
die DLL weiter, die erzeugt wurde.
Eigene Namens- Nicht zuletzt kCnnen Sie nat"rlich auch eigene Namensr>ume de-
r-ume finieren, die enthaltenen Klassen "bersetzen und auch so ge-
sch"tzten Code weitergeben. Um die Modularisierung auf die
Spitze zu treiben, steht jedem Modul die Wahl der Sprache frei.
Dank der IL schreiben Sie Ihre Module vielleicht in VB.NET, Ihr
Kollege in C# und der sp>tere Anwender bleibt bei JScript.NET
auf der Seite.
Script Limits ASP hat weit reichende Einschr>nkungen, die durch die Verwen-
dung einer reinen Skriptsprache bedingt sind. Entwickler m"ssen
hier oft auf Komponenten ausweichen, die in VB oder C++ ge-
schrieben wurden – in richtigen Programmiersprachen also. Das
ist nun nicht mehr notwendig. VB.NET ist eine »richtige« Pro-
grammiersprache und Sie m"ssen auf keine Funktion verzichten.
Alles, was vorher in Komponenten geliefert wurde, kann nun di-
rekt programmiert werden. Selbstverst>ndlich lassen sich fertige
Programme kompilieren und anderen zur Verf"gung stellen. Da-
mit einher geht nat"rlich auch ein Verlust der Einfachheit – statt
typloser Programmierung muss das sehr strenge Typsystem CTS
verwendet werden (siehe Abschnitt »Einf"hrung in das Common
Type System« ab Seite 154).
Verteilung Die Installation fertiger ASP-Anwendungen ist ein durchaus kom-
plizierter Vorgang, wenn es sich um ASP-Code handelt, der
COM-Komponenten enth>lt. ASP.NET-Anwendungen lassen sich
sehr leicht auf einem Entwicklungssystem erstellen und dann auf
einen Produktionsserver bringen. Es gen"gt, die fertigen Pro-
gramme zu kopieren. Weder Struktur noch Dateien m"ssen ge>n-
dert werden. Legen Sie auf dem Produktionsserver ein virtuelles
Verzeichnis an, kopieren Sie alle Daten dort hinein – fertig. Es ist
Sandini Bib
Unterschiede zum alten ASP 33
Die Integration von HTML-Code auf der einen Seite und Skript- Klassisch: HTML
sprache auf der anderen ist bei großen Projekten ein massives und Code
gemischt
Hemmnis f"r eine professionelle Softwareentwicklung. Der Code
zerfasert durch die Interaktion von HTML – was notwendigerwei-
se erzeugt werden muss – und den Programmmodulen, die ele-
mentare Aufgaben wie die Abfrage von Datenbanken erledigen.
Im Ergebnis sind solche Seiten mit herkCmmlichen HTML-Edito-
ren nicht mehr zu bearbeiten und der Code selbst ist oft derart un-
leserlich, dass eine Wiederverwendung unmCglich erscheint. Im
Endeffekt sollte diese Art Programmierung nur f"r sehr kleine
Aufgaben genutzt werden; die Entwicklung wird sonst fr"her
oder sp>ter sehr teuer. In viele F>llen wird sich mit Templatesys-
temen beholfen. Das sind Programme, die reine HTML-Vorlagen
mit eingebetteten Variablen verwenden und den Code kon-
sequent auslagern. Nachteilig ist die mangelnde Leistung, weil sie
bislang immer in der Skriptsprache programmiert wurden, f"r die
der Umgang erleichtert werden soll.
Die wichtigste Erkenntnis beim Umgang mit ASP.NET ist: ASP.NET ist ein
»ASP.NET ist ein Templatesystem«. Vielleicht haben Sie erwartet, Templatesystem
ASP.NET-Seiten- Damit das funktioniert, wird mit ASP.NET ein komplexer und
verarbeitung sehr strenger Seitenverarbeitungszyklus eingef"hrt. Bevor die ei-
gentliche Verarbeitung stattfindet, analysiert ASP.NET die Vor-
lage und erstellt aus allen entsprechend gekennzeichneten Ele-
menten Objekte. Diese Objekte geben dem Programmierer einen
Zugriff auf Inhalt, Attribute und verbundene Daten im eigentli-
chen Programm. Da in der Welt von .NET alles Objekte sind, steht
auch die Seite selbst als solches bereit. Bestimmte Zust>nde dieser
Objekte kCnnen Ereignisse auslCsen. ASP.NET ermCglicht bei der
Programmierung von Webserverapplikationen einen Stil, der dem
der Windows-Programmierung sehr nahe kommt. Aber nicht nur
das – alle Klassen des Frameworks, auch die grafischen Module
zum Erstellen grafischer Oberfl>chen – stehen zur Verf"gung. In
Abschnitt 11.2, »Bilder dynamisch erstellen« ab Seite 990 finden
Sie eine praktische Anwendung bei der dynamischen Erstellung
von Bildern. Die Ereignissteuerung ist raffiniert gekapselt. Wenn
Sie eine Schaltfl>che mit einer Methode so verbinden, dass die
Methode ausgef"hrt wird, wenn die Schaltfl>che angeklickt wur-
de, ist dies Ereignissteuerung. Das nat"rlich ein Formular abge-
sendet und die per POST gesendeten Daten ausgewertet werden,
bleibt weitgehend verborgen.
Vermeiden Sie den Bei den ersten Schritten mag es einfacher erscheinen, klassisch zu
klassischen Weg programmieren. Denn es stehen die von ASP bekannten Klassen
unter ASP.NET!
Request, Response usw. auch in ASP.NET zur Verf"gung. Und
nicht nur das, sie sind auch kr>ftig gewachsen und haben viele
neue und leistungsf>hige Methoden hinzubekommen. Nichtsdes-
totrotz ist der Einsatz relativ selten nCtig, denn die neuartige For-
mularverarbeitung ist sehr leistungsf>hig und spart viel Code, der
sonst m"hevoll programmiert werden m"sste. Das gilt auch f"r
clientseitigen JavaScript-Code. Hier liefert ASP.NET einige sehr
gute Bibliotheken mit, um Reaktionen zu realisieren, die mit
HTML alleine nicht mCglich sind. Diese Bibliotheken laufen "bri-
gens auch mit anderen Browsern als dem Internet Explorer. Tat-
s>chlich spielen sich alle .NET-spezifischen Dinge auf dem Server
ab. Im Browser kommt nichts als HTML, CSS und ebentuell Java-
Script an. Allerdings setzt Microsoft voraus, dass HTML 4- und
CSS 2-konforme Endger>te verf"gbar sind.
Sandini Bib
Vorbereitung auf ASP.NET 35
E Windows XP Professional
E Windows 2000 Professional (ab Service Pack 2)
E Windows .NET Server-Familie
E Windows 2000 Server-Familie (ab Service Pack 2)
Sie k5nnen auch ohne den IIS entwickeln. Die freie Entwicklungs-
umgebung Web Matrix bringt einen eigenen Webserver mit. Damit l:sst
sich eine Entwicklungsumgebung beispielsweise unter Windows XP
t
Home aufbauen, obwohl diese Version keinen IIS mitbringt.
Sandini Bib
36 1 Prinzip und Funktionsweise
.NET Framework Das .NET Framework selbst bietet Microsoft kostenlos an. Im
nachfolgenden Abschnitt finden Sie weiterf"hrende Informa-
tionen zur Beschaffung und Installation. Wenn Sie das Visual Stu-
dio einsetzen, brauchen Sie sich "brigens darum weniger Gedan-
ken machen – hier ist das Framework neben anderen Tools bereits
im Lieferumfang enthalten.
MDAC Wenn Sie Applikationen entwickeln wollen, die auf Datenbanken
zugreifen, werden Sie die Microsoft Data Access Components
(MDAC) benCtigen. Diese sind wie das Framework frei erh>ltlich
und momentan in der Version 2.7 aktuell. Auf den SQL-Server
(Version 7 oder 2000) kCnnen Sie direkt zugreifen und benCtigen
MDAC hierf"r nicht.
Editor Zum Eintippen der Codes brauchen Sie einen Editor. Im Grunde
reicht bereits der bei Windows standardm>ßig enthaltene Note-
pad aus. Allerdings werden Sie damit schwerlich produktiv arbei-
ten oder gar grCßere Projekte bew>ltigen kCnnen. Deutlich besser
geeignet sind professionelle Entwicklungswerkzeuge. Das wich-
tigste Werkzeug f"r die .NET-Programmierung, welches aller-
dings einiges kostet, ist derzeit das Visual Studio .NET. Dieses
wird in Kapitel 3 n>her behandelt.
IIS installieren
Zur Installation des IIS 5 auf einem der unterst"tzten Windows-
Betriebssysteme gehen Sie wie nachfolgend beschrieben vor. Die
einzelnen Schritte sind bei den Windows Client-Systemen (2000
und XP Professional) sowie den Serversystemen (2000 und .NET
Server) prinzipiell gleich. Gezeigt wird hier das Vorgehen bei ei-
ner Windows XP Professional Arbeitsstation.
Rffnen Sie zuerst "ber das Startmen" die Systemsteuerung und Installations-
starten Sie dort das Programm Software. Klicken Sie im dann fol- schritte
Auch wenn Sie das System nach der Installation nicht zu einem Neu-
t start auffordert: Starten Sie dennoch Ihr System neu, bevor Sie mit
weiteren Installationsschritten fortfahren. Einige Komponenten des IIS
arbeiten sonst unter Umst:nden noch nicht oder nicht richtig.
Wie der IIS F"r eine erste Orientierung sollten Sie sich das IIS-Arbeitsver-
arbeitet zeichnis anschauen. Der IIS legt ein Verzeichnis \inetpub an, das
folgende wichtige Unterverzeichnisse enth>lt:
E \iissamples
Hier sind einige Beispiele im alten ASP 3.0 zu finden.
E \scripts
Dieses Verzeichnis wurde zum Ablegen von ASP-Program-
men genutzt. Es spielt unter ASP.NET keine Rolle.
Sandini Bib
Vorbereitung auf ASP.NET 39
E \wwwroot
Das ist das Stammverzeichnis des Webservers; hier liegen die
Dateien, die ohne weitere Pfadangabe erreicht werden kCnnen.
E \webpub
Dieses Verzeichnis dient der Ablage von Dateien, die per Web-
DAV hochgeladen wurden. WebDAV ist eine HTTP-Erweite-
rung, die den Zugriff auf das Dateisystem eines Webservers
per HTTP erlaubt. Das Verzeichnis ist nach der Installation
leer.
E \ftproot und \mailroot
Dies sind die Stammverzeichnisse des FTP- und SMTP-Ser-
vers. Wenn Sie die Installation auf einem Windows 2000- oder
.NET Serversystem ausgef"hrt haben, finden Sie außerdem
noch \nntproot, das Stammverzeichnis des Newsservers.
Der IIS enth>lt einige Dateien, die f"r einen ersten Test benutzt IIS testen
werden kCnnen. Starten Sie dazu den Browser und geben dann
folgende Adresse ein: http://localhost.
Sie sollten dann das folgende Bild sehen. Sie kCnnen nun mit der
Installation des Frameworks fortsetzen.
Was tun bei Mit dem funktionierenden IIS kCnnen Sie die weiteren Schritte
Fehlern? ausf"hren. Zeigt der Browser einen Fehler an, sollten Sie erst fort-
fahren, wenn die Ursache gefunden ist. Gehen Sie dazu folgender-
maßen vor:
E Pr"fen Sie den Dienst WWW-Publishingdienst. Er muss
gestartet sein, damit der IIS arbeiten kann.
E Wenn das nicht die Ursache sein sollte, probieren Sie, statt
»localhost« den Namen des Computers anzugeben.
F"r die ersten Schritte mit ASP.NET reicht das kleine Paket aus.
Die bersetzung der Programme l>uft bei ASP.NET im Hinter-
grund beim Aufruf der Seite ab – zus>tzliche Compiler werden
nicht unbedingt benCtigt. Wenn Sie auf die Online-Hilfe zugreifen
mCchten, besuchen Sie die Website http://www.asp.NET.
Nach der Installation des Frameworks empfiehlt es sich, die Ein- IIS-Einstellungen
stellungen im IIS zu "berpr"fen. Ob die Verbindung von Frame- prfen
Neben den f"r den IIS "blichen Dateierweiterungen und den ent-
sprechenden Zuordnungen m"ssen nun auch die neuen .NET-Er-
weiterungen wie beispielsweise .aspx erscheinen. Ist das nicht der
Fall, ist die Ursache meist eine falsche Installationsreihenfolge. Sie
haben dann wahrscheinlich den IIS erst nach dem Framework in-
stalliert. Dies kann dann passieren, wenn Sie beispielsweise mit
Web Matrix beginnen zu entwickeln (das den IIS nicht braucht)
und sich erst sp>ter f"r ein anderes Werkzeug wie etwa Visual
Studio .NET entscheiden.
Framework-Installation reparieren
Framework im IIS Stellen Sie fest, dass die Zuordnungen im IIS nicht existieren, kCn-
registrieren nen Sie das Framework mit dem Aufruf des Dienstprogramms
aspnet_regiis.exe neu im IIS registrieren:
aspnet_regiis.exe /r
%Systemroot%\Microsoft.NET\Framework\<version>
Parameter Beschreibung
r Reinstalliert die momentane ASP.NET-Version in alle An-
wendungszuordnungen der IIS-Metabasis
c Reinstalliert die clientseitigen JavaScript-Bibliotheken f r
Webserver-Steuerelemente f r alle Websites
e Deinstalliert die clientseitigen JavaScript-Bibliotheken f r
Webserver-Steuerelemente f r alle Websites
Direkter Zugriff F"r den Zugriff auf den SQL-Server 7 oder 2000 aus ASP.NET-
auf MS SQL-Server Anwendungen brauchen Sie auf Ihrem System keine weiteren
Komponenten installieren. Lediglich das SQL-Serversystem selbst
muss lokal oder gegebenenfalls auf dem externen Entwicklungs-
Webserver installiert sein. Der Zugriff erfolgt "ber den so genann-
ten SQL Data Provider, einer integralen Komponente von
ADO.NET.
ODBC Benutzen Sie andere Datenbanksysteme, brauchen Sie zus>tzliche
Schnittstellen. Eine international standardisierte Schnittstelle ist
daf"r ODBC (Open Database Connectivity). ber diese kCnnen un-
ter Windows verschiedene relationale Datenbanken angesprochen
werden. Voraussetzung ist dabei, dass auf die betreffende Daten-
bank "ber eine standardisierte SQL-Syntax zugegriffen werden
kann.
OleDb Die Schnittstelle OleDb wurde von Microsoft entwickelt, um leis-
tungsf>hige Applikationen f"r verteilte Daten erstellen zu kCn-
nen. Im Gegensatz zu ODBC spielt dabei der Typ der Datenbank
(wie relational oder hierarchisch) oder die zu verwendende Ab-
fragesprachsyntax keine Rolle. Wichtig ist nur, dass zum Daten-
austausch mit der Anwendung eine Tabellenform verwendet wer-
MDAC den kann. ADO, ODBC und OleDb sind Bestandteil des Microsoft
Data Access Components (MDAC). In diesem Paket sind des Wei-
teren noch die Remote Data Services (RDS), die allerdings kaum
noch eine Rolle spielen, sowie diverse ODBC-Treiber und OleDb-
Datenanbieter. Aktuell ist heute (Mitte 2002) die Version 2.7. Sie
erhalten MDAC kostenlos "ber diese Website: http://www.
microsoft.com/data/download.htm. Das Paket ist ca. 5 MByte groß
und sollte in der deutschen Version geladen werden, wenn Sie ein
deutsches Windows verwenden.
MDAC in XP Pro Die Installation ist nicht notwendig, wenn Sie Windows XP Pro-
enthalten fessional verwenden. Hier ist MDAC 2.7 im Lieferumfang bereits
enthalten. Im Rahmen des automatischen Updates von Windows
XP wird auch diese Komponenten stets auf dem aktuellen Stand
gehalten.
zeigt, wie Sie im IIS eine neue Website anlegen und wie Sie diese
konfigurieren sollten, wenn Sie die ersten Schritte in ASP.NET mit
einem einfachen Editor vornehmen wollen.
http://www.asp.net/webmatrix/default.aspx
Neue Website Gehen Sie wie folgt vor, um ein Verzeichnis f"r eine neue Website
einrichten einzurichten:
3. Zugriffsberechtigungen
In diesem Schritt geben Sie die Berechtigungen zum Zugriff
an. Da ASP.NET ein Programm ist, m"ssen Sie neben Le-
sen und Skript auch Ausf hren aktivieren. F"r viele Bei-
spiele im Buch werden auch Schreibberechtigungen
(Schreiben) erwartet. Wenn Sie Durchsuchen aktivieren,
kCnnen Sie die fertigen Programme leichter ausw>hlen. F"r
ein Entwicklungssystem werden deshalb sinnvollerweise
alle Optionen aktiviert.
Dateierweiterung Damit der IIS den Code abarbeiten kann, sollten Sie diesen im vor-
aspx bereiteten Verzeichnis ablegen. Wichtigste Voraussetzung zur
Nutzung von ASP.NET ist dabei, dass diese Datei die Erweiterung
aspx aufweist. Geben Sie dann in der Adresszeile des Browsers
den gew>hlten Aliasnamen an:
http://localhost/aspdotnet/firsttest.aspx
Fehler aufspren MCglicherweise haben Sie sich vertippt. Dann reagiert der Com-
piler mit einer ausf"hrlichen Fehlerbeschreibung. Wenn nicht,
provozieren Sie ruhig einmal einen Fehler im Codeteil (umgeben
von dem Tag <script>), um ein Gef"hl f"r die Reaktion von
ASP.NET zu bekommen.
Sandini Bib
Vorbereitung auf ASP.NET 49
An dieser Stelle werden Sie sich vielleicht "ber das erste laufende Wie es
Programm freuen, aber sicher ist es interessanter zu wissen, wie funktioniert
Eine Analyse des Codes zeigt das Prinzip der Verarbeitung. Zu-
erst wird ein <script>-Tag eingesetzt, das dem Server zwei Dinge
Sandini Bib
50 1 Prinzip und Funktionsweise
Nun folgt der Code der Seite. Sub ist ein Schl"sselwort in VB.NET,
das eine Methode deklariert, die nichts zur"ckgibt. Der Name der
Prozedur ist festgelegt. Page_Load wird immer dann ausgef"hrt,
wenn die Seite geladen wurde:
Sub Page_Load()
End Sub
<head><title>Erster Test</title></head>
<body>
<h1>Willkommen</h1>
Nein, diesmal nicht "Hello World".<br/>
Eine Datumsausgabe:
Die einzige Besonderheit ist das spezielle ASP-Tag, dass den Text
ausgibt. <asp:label> kann nicht mehr, als die Zeichenkette, die die
Eigenschaft Text enth>lt, auszugeben:
Sandini Bib
Grundlagen der Webserverprogrammierung 51
ASP.NET erscheint auf den ersten Blick recht einfach. In der Pra-
xis kommt dann doch etwas mehr auf Sie zu. Das liegt aber weni-
ger an der Notwendigkeit, alles zu verwenden, damit "berhaupt
etwas l>uft, sondern mehr an den MCglichkeiten, die die gelieferte
Technik bietet:
Einf hrung
HTTP dient der Kommunikation mit Webservern. Es gibt zwei
Versionen, 1.0 und 1.1. Auf Seiten der Browser dominiert inzwi-
schen HTTP 1.1, denn alle Browser ab Version 4 beherrschen die-
ses Protokoll. Der Internet Information Server ab Version 5.0 be-
herrscht die Version 1.1 vollst>ndig.
RFC 1945 HTTP 1.0 wurde im Mai 1996 in der RFC 1945 verCffentlicht,
Verbindungsloses schon im August desselben Jahres folgte HTTP 1.1. Bei HTTP han-
Protokoll delt es sich um ein verbindungs- oder statusloses Protokoll. Server
und Client nehmen also nie einen besonderen Zustand ein, son-
dern beenden nach jedem Kommando den Prozess vollst>ndig,
entweder mit Erfolg oder mit einer Fehlermeldung. Es obliegt
dem Kommunikationspartner, darauf in angemessener Weise zu
reagieren.
Protokollaufbau, HTTP-Kommandos werden als ASCII-Text "bertragen und kCn-
Header, Body nen aus mehreren Zeilen bestehen. Die erste Zeile ist immer die
Kommandozeile. Daran angeh>ngt kann ein so genannter Mes-
sage-Header (Kopf der Nachricht) folgen. Der Nachrichtenkopf
enth>lt weitere Parameter, die das Kommando n>her beschreiben.
So kann ein Content-Length-Feld enthalten sein. Steht dort ein Wert
grCßer als 0, folgen dem Nachrichtenkopf Daten. Die Daten wer-
den also gleich zusammen mit dem Kommando gesendet, man
spricht dann vom Body (NachrichtenkCrper) der Nachricht. HTTP
versteht im Gegensatz zu anderen Protokollen den Umgang mit
8-Bit-Werten. Bin>rdaten, wie Bilder oder Sounds, m"ssen nicht
konvertiert werden. Folgen dem HTTP-Kommando und den
Nachrichtenkopf-Zeilen zwei Leerzeilen (Zeilenwechsel), so gilt
das Kommando als beendet. Kommandos mit NachrichtenkCrper
haben kein spezielles Ende-Zeichen, das Content-Length-Feld be-
stimmt, wie viele Bytes als Inhalt der Nachricht betrachtet wer-
den.
Kommandoaufbau
Aufbau eines Ein HTTP-Kommando hat immer folgenden Aufbau:
HTTP-Kommandos
METHODE ID VERSION
Sandini Bib
Grundlagen der Webserverprogrammierung 53
Kommando Bedeutung
DELETE Ressource lCschen
GET Ressource anfordern
HEAD Header der Ressource anfordern
LINK Verkn pfung zweier Ressourcen beantragen
OPTIONS Optionen des Webservers erfragen
POST Formulardaten an einen Serverprozess senden
PUT Ressource auf dem Webserver ablegen
TRACE Kommando zur ckschicken lassen
UNLINK Verkn pfung zwischen Ressourcen lCschen
HTTP-Statuscodes
Die Antwort auf ein Kommando besteht im Senden der Daten – Statuscodes
wenn dies gefordert wurde – und einem Statuscode. Dem Status-
code folgen optionale Felder und, bei der bertragung von Res-
sourcen, die Daten. Die Statuszeile hat folgenden Aufbau:
VERSION STATUSCODE STATUSTEXT
Der Statuscode ist eine dreistellige Zahl, von der die erste Ziffer
(Hunderterstelle) die Zuordnung zu einer bestimmten Gruppe an-
zeigt.
Sandini Bib
54 1 Prinzip und Funktionsweise
HTTP-Code Bedeutung
200 Kommando erfolgreich (nach GET/POST)
201 Ressource wurde erstellt (nach PUT)
202 Authentifizierung akzeptiert (nach GET)
204 Kein Inhalt oder nicht angefordert (GET)
301 Ressource am anderen Ort
302 Ressource nicht verf gbar (temporFrer Zustand)
304 Ressource wurde nicht verFndert (steuert Proxy)
400 Syntaxfehler (alle Kommandos)
401 Keine Autorisierung
403 Nicht Cffentlicher Bereich
404 Nicht gefunden (GET)
500 Serverfehler, Fehlfunktion
502 Kommando nicht implementiert
Sie werden den Fehler 404 sicher kennen. Kennen lernen werden
Sie auch den Fehler Nummer 500, der erzeugt wird, wenn ein Pro-
gramm nicht funktioniert, das Sie in ASP.NET geschrieben haben.
MIME steht fBr Multipurpose Internet Mail Standard und definiert, wie
bestimmte Dateiarten Bber Internet Bbertragen werden k5nnen. MIME
wird nicht nur mit E-Mail, sondern unter anderem auch mit HTTP ein-
gesetzt. Mehr dazu finden Sie im Exkurs »Was ist eigentlich MIME?«
auf Seite 764.
E F
Frage-Felder (Request-Header-Fields), die nur in Kommandos
erlaubt sind
E A
Antwort-Felder (Response-Header-Fields), die Statusnachrich-
ten vorbehalten sind
Sandini Bib
Grundlagen der Webserverprogrammierung 55
E I
Informationsfelder (General-Header-Fields), dienen der ber-
tragung aller anderen Nachrichten in die eine oder andere
Richtung
Der Ablauf ist also recht simpel. Praktisch wird in diesem Beispiel
eine Datei mit dem Namen default.aspx angefordert. ASP.NET
Sandini Bib
56 1 Prinzip und Funktionsweise
startet dann, f"hrt den Code in der Seite aus, produziert den In-
halt der Seite und gibt ihn zusammen mit den richtigen Headern
an den Webserver. Dieser setzt den Code 200 – Alles OK – davor
und sendet alles an den Browser. Das der Benutzer dann mit den
Daten etwas anfangen kann, daf"r sind Sie verantwortlich. Den
Rest kCnnen Sie vorerst ASP.NET und dem IIS "berlassen. Profis
wissen nat"rlich, dass sich hier trickreich eingreifen l>sst. Im Nor-
malfall ist das aber nicht notwendig.
Zuerst fordert also der Nutzer mit seinem Browser ein Programm
an. Der gesamte Vorgang ist letztlich benutzergesteuert, was die
Art der Programmierung wesentlich von der Windows-Program-
mierung unterscheidet, auch wenn ASP.NET einige Tricks ein-
setzt, um den Unterschied kleiner werden zu lassen. Der Web-
server leitet diese Anfrage aufgrund der Dateierweiterung an ein
bestimmtes Programm weiter, bei ASP.NET an das ASP.NET-
Modul asp_isapi.dll. Dort wird die Seite durchsucht und darin ent-
haltene Codes werden ausgef"hrt. Daraus entsteht wiederum
HTML-Code, einschließlich der Daten aus Datenbankabfragen
Sandini Bib
58 1 Prinzip und Funktionsweise
<html>
<head><title>Erster Test</title>
</head>
<body>
<h1>Willkommen</h1>
Nein, diesmal nicht "Hello World".<br/>
Eine Datumsausgabe: É
Heute ist der <span id="datum">8.3</span>
</body>
</html>
Listing 1.3: Quelltext des Testprogramms im Browser
E Die .NET-Vision
Hier hat Microsoft seine Version der nahen Zukunft der Nut-
zung des Internet manifestiert. Dabei geht es darum, dass alle
elektronischen Ger>te "ber ein weltumspannendes und "berall
verf"gbares Breitbandnetzwerk verbunden sind. Damit einher
geht eine andere Art der Software- und Dienstleistungsvertei-
lung, in deren Mittelpunkt die Webservices stehen.
E Das .NET-Framework
Um Entwickler wie Anwender mit den Technologien zu ver-
sorgen, wird ein großer Teil der Dienste als Framework gelie-
fert. Sie haben es bereits erfolgreich installiert, es ist also nicht
mehr und nicht weniger als ein großes St"ck Software.
E Die .NET-Server
Um in lokalen oder globalen Netzwerken selbst Dienstleistun-
gen anbieten zu kCnnen, mit denen die Vision in Erf"llung ge-
hen kann, werden Enterprise Server eingesetzt. Dazu gehCren
der SQL Server 2000 und der BizTalk Server 2000. Beide basie-
ren, ebenso wie die zahlreichen anderen Server, noch nicht auf
dem .NET-Framework, nutzen aber die Technologie. Dies gilt
auch f"r die Windows Server 2003, die Nachfolger der Win-
dows 2000 Server.
Sandini Bib
60 1 Prinzip und Funktionsweise
Mit .NET >ndert sich an dieser Stelle etwas. Zum einen werden
ASP.NET-Programme, ebenso wie jede andere Anwendung,
grunds>tzlich compiliert. Das haben Sie bereits getan und es ver-
mutlich nicht einmal bemerkt. Tats>chlich dauert der erste Aufruf
einer ASP.NET-Seite etwas l>nger als alle folgenden. Die
ASP.NET-Komponente erkennt, dass die Seite noch nicht "ber-
setzt wurde und f"hrt die bersetzung sofort und ohne jede Inter-
aktion aus. Sie kCnnen das zwar durch diverse Eintr>ge in den
Code steuern, m"ssen es aber nicht. Dem Compiler ist damit der
Schrecken genommen. Fehlermeldungen werden in einer gut les-
baren Form an den Browser gesendet. Die bersetzung erfolgt je-
doch nicht direkt in nativen Maschinencode f"r die CPU, sondern
in eine Zwischensprache – die bereits erw>hnte MSIL. Dies ist ein
maschinennaher Code, der sehr viel schneller abgearbeitet wer-
den kann, als es ein Interpreter mit dem Quellcode kCnnte. Dieser
Code wird von der Common Language Runtime (CLR) aus-
gef"hrt, letztlich eine Art spezieller Compiler. Dieser Compiler ist
ein so genannter Just-In-Time-Compiler (JIT-Compiler). Er "ber-
setzt ein St"ck Code beim Abruf in Maschinensprache und spei-
chert ihn dann, sodass nur bei Pnderungen eine erneute berset-
zung notwendig wird.
Common Type In der .NET-Welt ist weiterhin immer wieder von den Klassen des
System Frameworks die Rede, genannt Basisklassen. Diese Klassen liefern
alles, was im Programmieralltag benCtigt wird. Vor allem aber –
und dies ist ein Unterschied zu anderen Klassensystemen – liefern
sie auch ein einheitliches Typsystem. Bislang kannte jede Pro-
grammiersprache eigene Datentypen; Ganze Zahlen (Integer), Zei-
chenketten oder komplexe Typen wie Arrays. Wenn nun ein Teil
in C# und ein anderer in VB.NET geschrieben wird, beide aber rei-
bungslos zusammenarbeiten m"ssen, funktioniert das nur, wenn
sich auch die Datentypen angleichen. Dies w"rde jedoch zu Kom-
promissen in allen eingesetzten Sprachen f"hren. Deshalb sind
diese Spracheigenschaften in das Common Type System (CTS)
ausgelagert.
Die Wahl der Datentypen und deren Pr>sentation ist von großer
Bedeutung bei der Programmierung. Wenn Sie bereits JScript oder
VBScript programmiert haben, werden Sie den Begriff »Datentyp«
nur am Rande registriert haben. Skriptsprachen arbeiten typlos
oder mit sehr losen Typen, die zur Laufzeit vom System selbst
vergeben werden. .NET basiert auf einem sehr strengen Typkon-
zept – dies gilt f"r alle Sprachen gleichermaßen. Sie m"ssen sich
also stets Gedanken dar"ber machen, welchen Typ eine Variable
besitzen soll, das heißt, welche Datenart darin gehalten wird. Typ-
bezeichner stehen nat"rlich weiterhin zur Verf"gung. Intern gibt
es aber ein Verkn"pfung zwischen dem vom Framework geliefer-
ten und dem in der Sprache definierten Typ.
Allen Bestandteilen liegt die Common Language Runtime zugrun- Grundlage: CLR
de. Darauf setzen die Basisklassen auf. Basisklassen sind solche
f"r einfache Datenmodelle (System.Collections), Multithreading
(System.Threading) oder IO (System.IO) f"r den Zugriff auf das Da-
teisystem. Von den Basisklassen abgeleitet und erg>nzt folgen die
Klassenbibliotheken. Dazu gehCren die Bibliotheken f"r den Da-
tenbankzugriff ADO.NET, die XML-Bibliotheken oder solche f"r
regul>re Ausdr"cke. Noch komplexere Aufgaben erledigen die
Klassen, die f"r den Anwendungsprogrammierer interessant sind:
ASP.NET, WinForms und Webservices sind die wichtigsten Ver-
treter. In diesem Buch wird ASP.NET behandelt. Verwechseln Sie
das nicht mit Webservices, die zwar auch auf Webservern aus-
gef"hrt werden, aber nicht einen Browser als Client erwarten, son-
dern einen anderen Server.
Der Fokus ASP.NET bedeutet aber nicht, dass die anderen Stufen
außer acht gelassen werden kCnnen. In vielen Abschnitten werden
immer wieder Klassen aus allen drei Stufen der Bibliotheken ver-
wendet werden. Dabei muss ein Zugriff auf eine Basisklasse keines-
falls komplizierter sein, als der auf eine Anwendungsklasse.
Die Kunst beim Umgang mit dem Framework besteht im Wesent- Referenz
lichen darin, bei Bedarf den passenden Namensraum und darin
die richtige Klasse zu finden. Die Online-Referenz ist dabei ein
sehr wichtiges Arbeitsmittel, im Web unter folgender Adresse zu
finden:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/
html/cpref_start.asp
Sandini Bib
64 1 Prinzip und Funktionsweise
Wenn es schwer ist, warum legt Microsoft dann solchen Wert da-
rauf, die Welt der Objekte zur alleinigen Herrschaft in der Pro-
grammierwelt zu f"hren? In einfachen Applikationen, die nur we-
nige Zeilen Code enthalten, gibt es tats>chlich kaum Vorteile.
Wenn jedoch grCßeren Anwendungen geschrieben werden, wof"r
auch ASP.NET bestens geeignet ist, dann wird es schwer, die
bersicht zu behalten. Der erste Schritt besteht darin, Techniken
zu schaffen, die Codes wiederverwendbar machen. Dadurch wer-
den Programme kleiner und die Fehlerquote sinkt, weil man auf
gepr"fte und ausgereifte Module zur"ckgreifen konnte. Im alten
ASP war die einzige MCglichkeit der Modularisierung die Ver-
wendung der SSI-Anweisung INCLUDE. Das ist vCllig unzureichend,
wenn man die MCglichkeiten der objektorientierten Programmie-
rung daneben stellt.
Was ist ein Ein Objekt in Software – hier immer vereinfacht als Objekt be-
Objekt? zeichnet – ist eine Sammlung von Code, der etwas aus der realen
Welt konkret beschreibt. Das kCnnen Dinge wie Tiere oder Autos
sein, aber auch Zust>nde oder Pl>ne wie Kalender oder Aufgaben.
Man kann alles in der realen Welt als Objekt betrachten und des-
halb ist die Abbildung in einer >hnlich Form in Software eigent-
lich genial. Objekte kCnnen in weitere, kleinere Objekte zerfallen.
Sandini Bib
Grundprinzip der Programmierung mit ASP.NET 65
Stellen Sie sich ein Auto vor. Es zerf>llt in Bauteile wie R>der, T"-
ren, den Motor usw. Jedes Teil teilt sich wiederum in weitere Bau-
teile. Treibt man diese berlegung sehr weit, endet man bei den
Elementarteilchen. Irgendwo zwischen Elektronen und Quarks
gibt es ein Basisobjekt.
Der Vorgang von der Abbildung realer Dinge in Software wird als
Abstraktion bezeichnet. Als Programmierer muss man deshalb
nicht nur logisch sondern auch abstrakt denken kCnnen. Sie ver-
suchen dabei das, was Sie aus der Realit>t abbilden mCchten, in
ein abstraktes Modell zu packen. Je besser Ihnen das gelingt, desto
einfacher und stringenter ist die LCsung. Guter objektorientierter
Code hat einige Eigenschaften:
Das klingt alles sehr gut, ist aber in der Praxis nur mit einiger Er-
fahrung zu erreichen. .NET hilft Ihnen aber dabei, denn wenn al-
les ein Objekt ist und VB.NET nun eine echte objektorientierte
Programmiersprache, dann kann das Schreiben entsprechenden
Codes nicht schwer sein. Objekt haben Eigenschaften. Das ist not- Objekte haben
wendig, um Dinge zu beschreiben. Die Wahl der passenden Ei- Eigenschaften
Objekte haben bar – wie in der realen Welt. Dinge haben nicht nur Eigenschaften,
Methoden sie kCnnen auch Aktionen ausf"hren. Ein Auto kann fahren oder
T"ren Cffnen und schließen. Steigt man in der Objekthierarchie
wieder noch unten – zur Wurzel hin, werden andere Methoden
interessant. So w>re f"r das Getriebe eine Methode »Gang hCher«
oder »Gang niedriger« interessant. Eine Methode »3. Gang« ist da-
gegen nicht sinnvoll, weil es nicht immer mCglich und sinnvoll
sein kann, direkt in einen Gang zu schalten. Dagegen ist eine Ei-
genschaft »Gang« besser geeignet, da dort der aktuelle Zustand
abgefragt werden kann. Eben diese berlegungen sollten auch bei
Software angestellt werden, was nicht so schwer ist, weil es nur
um die Abbildung realer Dinge geht – theoretisch jedenfalls.
Systemtypen sind in .NET alles, was die Basis f"r Objekte ist. Dies
sind die schon erw>hnten Klassen, aber auch komplexe Struktu-
Sandini Bib
Grundprinzip der Programmierung mit ASP.NET 67
brigens wird oft auch keine richtige Klasse geschrieben und ein
Objekt daraus abgeleitet. Viele ASP.NET-Beispiele sehen wie kon-
ventioneller prozeduraler Code aus. Tats>chlich nutzt aber
ASP.NET Klassen des Frameworks, um aus Ihrem Code komplet-
te objektorientierte Quellen zu erzeugen und diese dann zu "ber-
setzen. Dies ist ein Trick, der den Einstieg in ASP.NET vereinfacht
und von dem Windows-Programmierer nicht profitieren kCnnen.
Mehr Vorteile f"r ASP.NET-Entwickler werden im n>chsten Ab-
schnitt gezeigt.
von Windows ab, sondern ist sowohl sichtbar als auch kontrollier-
bar. ASP.NET erzeugt in einem ersten Lauf aus der Seite, die so-
wohl HTML als auch Code in einer der .NET-Sprachen enth>lt, ei-
ne so genannte »Page«. Der Page-Compiler erstellt daraus eine
Page-Klasse, wozu auf verschiedene Basisklassen zur"ckgegriffen
wird (System.CodeDOM und System.DLL). Diese Klasse wird "bersetzt
und als Assembly abgelegt.
Assemblies Assemblies sind die Nachfolger der DLLs, wobei die Dateierwei-
terung dll erhalten geblieben ist. Assemblies enthalten viele Zu-
satz- und Konfigurationsinformationen, sodass die Verwaltung
einfacher und sicherer ist, als bei DLLs. Wenn Sie das erste Bei-
spiel ausgef"hrt haben, kCnnen Sie die DLL bereits sehen. Sie ist
in folgendem Pfad zu finden:
%Systemroot%
\Microsoft.NET
\Framework
\<version>
\Temporary ASP.NET Files
Im Kern basiert ASP.NET auf einer HTTP-Applikation, der HTTP- Das Konzept der
Laufzeitumgebung. Diese Komponente empf>ngt von der ISAPI- »Handler«
Anwendung die Anforderung (so genannter Request vom Browser)
und leitet sie "ber Module – die sie programmieren kCnnen – an
den Request Handler weiter. Dieser Teil ist f"r die Ausf"hrung des
angeforderten Codes verantwortlich. Er kann aber auch nur ein-
fache statische Seiten ausliefern, wenn diese zwar wegen der Er-
weiterung .aspx den Prozess in Gang setzten, aber keine Program-
mierung enthielten. Was im Wesentlichen hier erledigt wird, ist die
korrekte Nutzung des Protokolls HTTP. Dar"ber m"ssen Sie sich
keine Gedanken machen. Es ist aber auf der anderen Seite hilfreich,
HTTP zu kennen. Denn dann f>llt es Ihnen leichter zu verstehen,
was die entsprechenden Methoden und Eigenschaften der HTTP-
Handler-Klassen bedeuten und wie man sie sinnvoll in der Pro-
grammierung einsetzen kann. Der n>chste Abschnitt bietet deshalb
unter anderem eine kompakte Einf"hrung in das Protokoll HTTP.
Applikations-Zyklus
Server
Request “Beginn Request”
Seite laden
Status herstellen
Response Seite ausführen
Status speichern
Filter verwenden
Daten
“End Request”
Wenn Sie sich mit dem Zyklus der gesamten Seite auseinander
setzen, ist es auch wichtig zu verstehen, dass jedes Steuerelement
– beispielsweise ein Eingabefeld – ebenfalls einen solchen Zyklus
durchl>uft.
Der Zyklus der Die folgende Tabelle zeigt die Phasen und deren Aktivit>ten so-
Steuerelemente wie das zugeordnete Ereignis und den Namen der dazu passen-
den Ereignisbehandlungsmethode, wie es f"r jedes Steuerelement
der Seite durchlaufen wird. Anschließend wird auf den globalen
Zyklus der Seite eingegangen.
Sandini Bib
Grundprinzip der Programmierung mit ASP.NET 73
Dieser Zyklus wird nun f"r jedes Element durchlaufen. Die Daten
werden jeweils gesammelt, da "blicherweise viele Steuerelemente
auf einer Seite platziert sind.
Der Zyklus der Seite durchl>uft eine >hnliche Phase, wie sie f"r Der Zyklus der
jedes Steuerelement auftreten. Auch hier bestehen Eingriffs- Seite
Die folgende Tabelle zeigt die Phasen, deren Bedeutung und die
zugeordneten Ereignisse und deren Ereignisbehandlungsmetho-
den.
Sandini Bib
74 1 Prinzip und Funktionsweise
Der Zyklus der Steuerelemente wird also in der Phase der Initiali-
sierung (Phase 1) des Lebenszyklus der Seite durchlaufen. Sie
kCnnen deshalb im eigenen Code nicht Pnderungen an Steuerele-
menten vornehmen, die vor dem Zuweisen des Status notwendig
w>ren.
Bleibt zuletzt noch ein Blick auf den Aufr>umprozess. Bevor die
Seite endg"ltig aus dem Speicher verschwindet – Page_UnLoad wird
zuvor aufgerufen – ist ein guter Zeitpunkt, beispielsweise nicht
persistente Verbindungen zu einer Datenbank zu schließen.
Sonstige Ereignisse
Neben diesen, in der normalen Programmierung h>ufig benCtig- PreRender
ten Ereignissen gibt es weitere, die nur unter bestimmten Bedin- Error
Was hat das zu bedeuten? Hier wird f"r das Ereignis »Page_
Load« eine Ereignisbehandlungsmethode definiert. Diese "ber-
schreibt die vom System vorgegebene, damit dort eigene Auf-
gaben ausgef"hrt werden kCnnen. bergeben wird der Methode
das aufrufende Objekt im ersten Parameter, allgemein als sender
bezeichnet (tats>chlich ist der Name frei w>hlbar) und immer
vom Typ Object. Der zweite Parameter enth>lt das so genannte Er-
eignisargument, das bei den Standardereignissen der Seite vom
Typ EventArgs ist. Auch hier wird h>ufig als Name e verwendet,
aber auch dies ist frei w>hlbar.
Programmierung Wenn Sie Code mit dem Designer des Visual Studio .NET erzeu-
im Visual Studio gen, wird das Resultat etwas anders aussehen. Hier wird die Er-
.NET
eignisbehandlungsmethode immer als private gekennzeichnet. Sie
ist damit f"r den direkten Aufruf nicht sichtbar. Der Designer f"gt
daf"r folgenden Code in Ihre Code-Datei ein, damit die Ausf"h-
rung dennoch gelingt:
End Sub
#End Region
Sandini Bib
Programmierprinzipien 77
End Class
1.5 Programmierprinzipien
Dieser Abschnitt f"hrt in die grundlegenden Prinzipien von
ASP.NET ein. Die ausf"hrliche Betrachtung folgt dann im Teil B.
Diese Einf"hrung dient der systematischen Vorbereitung der nCti-
gen Fertigkeiten in den folgenden Kapiteln, in denen die Grund-
lagen der ASP.NET-Programmierung vermittelt werden.
Imports System
Imports System.Web
Imports System.Web.UI
Imports System.Web.UI.WebControls
Imports System.Web.UI.HtmlControls
Imports System.Collections
Sie kCnnen also die externe Code-Datei und die verwendete Klas-
se getrennt erreichen. Dadurch ist es mCglich und oft sinnvoll,
mehrere Klassen in einer Datei unterzubringen. Beachten Sie bei
der Angabe der Klasse, dass auch der Namensraum erforderlich
ist, wenn einer verwendet wurde. Die Beispiele im Buch liegen
unter »Addison.VBNet«, in diesem Kapitel ist noch eine weitere
Interessant ist nur die erste Zeile, die die zu verwendende Klasse
und die Quelldatei festlegt. Die eigentliche Arbeit steckt in der vb-
Datei:
Imports System
Imports System.Web
Imports System.Web.UI
Imports System.Web.UI.WebControls
Imports System.Web.UI.HtmlControls
Sandini Bib
82 1 Prinzip und Funktionsweise
Imports System.Collections
Namespace Addison.VBNet.WebForm
Public Class CodeBehind
Inherits System.Web.UI.Page
End Class
End Namespace
Listing 1.5: Code Behind-Datei (codebehind.aspx.vb)
Damit aus der Seite heraus auf die instanziierten Seitenobjekte zu-
gegriffen werden kann, wie das beispielsweise f"r die Schaltfl>che
btn gezeigt wird, m"ssen diese als Protected (oder Public) dekla-
riert werden:
Außerdem ist nat"rlich der richtige Datentyp anzugeben. Der Zu- Datentypen
griff "ber globale Klassen, wie HtmlControl statt HtmlInputControl
funktioniert zwar, schr>nkt aber die verf"gbaren Eigenschaften
und Methoden entsprechend ein.
Hier wird die Datei selbst mit dem Attribut Codebehind angegeben.
Das Attribut Inherits gibt die Klasse an, die verwendet werden
soll. Diese Klasse muss von Page erben.
mit ist .NET weit besser f"r den Betrieb bei einem Massenhoster
geeignet, als die Vorg>ngerversion ASP.
1.6.1 Sicherheitskonzepte
Um f"r einen Webserver f"r optimale Sicherheit zu sorgen, sollten
Sie sich zuerst mit den prinzipiellen Sicherheitskonzepten aus-
einander setzen:
E Softwaresicherheit
Auch wenn es sich banal anhCrt: Das Aufpielen der neuesten
Service Packs; Sicherheits-Updates und die Umsetzung von Si-
cherheitshinweisen des Softwareherstellers ist eine Pflicht-
"bung.
E Authentifizierung
Hierunter wird die Erkennung eines Benutzers verstanden
(»Wer bin ich?«). Falls es sich nicht um einen anonymen Zu-
gang handelt, wird sich der Benutzer in der Regel mit Name
und Kennwort identifizieren. Das gilt auch – wenn auch "ber
Umwege – f"r die Nutzung von Diensten wie Passport. An-
sonsten kann die Authentifizierung "ber den IIS und die inte-
grierten Sicherheitsmodelle von Windows 2000 bzw. .NET-
Server erfolgen.
E Autorisierung
Nachdem sich ein Benutzer authentifiziert hat, ist es Aufgabe
der Autorisierung festzustellen, welche konkreten Rechte er
hat. Hiermit wird also festgelegt, welche Ressourcen er lesen,
ausf"hren oder schreiben darf. Damit das in der Praxis nicht
zu kompliziert wird, bieten der IIS und ASP.NET einige vor-
definierte Konten, die standardm>ßig zum Einsatz gelangen.
E Impersonifizierung
Ist ein Benutzer identifiziert, kann ein vorher unter einem
Standardkonto ablaufender Prozess die Identit>t des Benutzers
annehmen. Dieser Vorgang wird als Impersonifizierung be-
zeichnet. Damit wird vor allem die Rechtevergabe erleichtert,
ohne dass eine Schwachstelle in der Sicherheitskette aufgeris-
sen wird.
Die erste Frage ist immer wieder: Deutsch oder Englisch? Prinzi- Deutsch oder
piell ist es egal, solange Sie nicht mitten im Programm die Sprache Englisch
E Pascal-Schreibweise
Diese Schreibweise nutzen Großbuchstaben zur Trennung von
Wortteilen, beispielsweise CodeKonvention. Das Wort beginnt
außerdem immer mit einem Großbuchstaben. Diese Schreib-
weise ist die Standardform in .NET und wird f"r Klassen, Na-
mensr>ume, Eigenschaften und Cffentliche Variablen verwen-
det.
E Camel-Schreibweise
Bei dieser Schreibweise wird >hnlich wie bei der Pascal-
Schreibweise ein Großbuchstabe zur Trennung der Wortteile
eingesetzt. Der erste Buchstabe ist jedoch immer klein. Da-
durch entsteht in der Mitte eine Art HCcker, was zur Namens-
vergabe f"hrte: blueHeader.
Einsetzen sollten Sie diese Schreibweise f"r Parameter, die ei-
ner Methode "bergeben werden.
Sandini Bib
86 1 Prinzip und Funktionsweise
E Großbuchstaben
Reine Großbuchstabenfolgen sollten nur in Ausnahmef>llen
verwendet werden. Wenn Sie viel mit Konstanten arbeiten, ist
eine Kennzeichnung manchmal hilfreich: START.
Wenn ein Bezeichner nur aus zwei Buchstaben besteht, kCnnen
Großbuchstaben die Lesbarkeit steigern: System.IO.
Generell ist Schnittstellennamen ein großes »I« voranzustellen
(von Interface): IComparable.
E Kleinbuchstaben
Lokale Variablen, die einen geringen Sichtbereich haben oder
tempor>r existieren, Schleifenvariablen und andere Hilfsvaria-
blen sollten mit Kleinbuchstaben gekennzeichnet werden:
i, temp.
Firma.TechnologieOderProjekt.Funktion.Teilfunktion
Dagegen sollten Sie nicht den Typ als Namen verwenden. Falsch
w>re danach: doubleValue. Dies ist nicht aussagekr>ftig. Verwen-
den Sie viele verschiedene Typen und ist die Unterscheidung f"r
den Leser von großer Bedeutung, kann der Typ in seiner all-
gemeinsten Form vorangestellt werden: dSchalterWert, f"r einen
Double-Typ. Verwenden Sie nicht die voll ausgeschriebenen Ty-
pen der verwendeten Programmiersprache, weil diese im Dis-
assembler in Systemtypen verwandelt werden und dann solche
Bezeichnungen irref"hrend sind.
Bei statischen Feldern sollten Sie immer den Typ davor setzen.
Dies dient der Erkennbarkeit "ber weite Strecken, weil diese Fel-
der nicht instanziiert werden.
MyButton_Click
Dabei ist es "blich – und dies ist die Ausnahme – bei einer deut-
schen Benennung der Steuerelemente den urspr"nglichen Namen
des Ereignisses zu belassen: Schalter_Click ist besser als Schalter
_Klick.
Sandini Bib
Hinweise zum Stil – Codekonventionen 89
E Code-Konventionen einhalten
E Formatierung und Strukturierung beachten
ASP.NET unterstBtzt Sie dabei mit einer ganze Reihe von Techniken,
von denen so genannter hinterlegter Code (Code Behind) die wichtigste
ist. Diese Technik wird deshalb in diesem Buch dominant eingesetzt.
ASP.NET verfBgt Bber eine ganze Reihe von Techniken, mit denen Da-
ten zwischengespeichert werden k5nnen oder die der Kontrolle von Zwi-
schenspeichern (Caches) dienen. Setzen Sie sich damit aktiv auseinander,
um professionelle Webapplikationen zu erhalten.
Sandini Bib
Voraussetzungen
Vor der Installation sollten Sie pr"fen, ob Ihr Entwicklungssystem Hohe Hardware-
einige Voraussetzungen erf"llt. Visual Studio stellt insbesondere Anforderungen
an die zu verwendende Hardware recht hohe Anforderungen:
Wenn Sie das Studio starten, wird jedoch zuerst die Startseite an-
gezeigt (siehe Abbildung 2.3).
Sandini Bib
96 2 Visual Studio .NET
Weitere Fenster lassen sich "ber das Men" Ansicht ein- und aus-
blenden. Am Anfang sollten Sie sich mit dem Projekt-Explorer
besch>ftigen, denn f"r die Projektverwaltung ist Visual Studio
.NET gut geeignet.
Sandini Bib
berblick :ber die IDE 97
Generell gilt also: Die oberste logische und physische Ebene bildet ein
Projekt. Die logische Strukturierung innerhalb des Projekts erfolgt mit
Namensr:umen. Die Aufteilung auf Dateien hat keinen Einfluss auf das
fertige Programm. Sie k5nnen einzelne Dateien nicht Bbersetzen oder zu
einer eigenst:ndigen Assembly werden lassen. Sie k5nnen aber Dateien
aus einem Projekt ausschließen, wenn Sie deren Code nicht mehr ben5ti-
gen. Dazu muss die Datei nicht gel5scht werden.
Damit ist die Mappe fertig. F"gen Sie nun ein Projekt hinzu, das
sp>ter die Code-Dateien und andere Ressourcen aufnimmt.
Sandini Bib
berblick :ber die IDE 99
Mit dem Anlegen des Projekts f"hrt Visual Studio .NET einige
Schritte aus, die sp"rbar Zeit beanspruchen:
E AssemblyInfo.vb
Eine Informationsdatei, mit der das Manifest der erzeugten
Assembly gesteuert wird. Dies kCnnen Sie vorerst unbeach-
tet lassen.
E Global.asax
Diese Datei – und die im Projekt-Explorer unsichtbare
Code-Datei Global.asax.vb – dient der Programmierung von
verschiedenen Ereignissen, die w>hrend der Seitenver-
arbeitung auftreten.
E <Projektname>.vsdisco
Diese Datei dient als Informationsquelle f"r andere Server,
wenn Sie Webservices programmieren. Normalerweise
kCnnen Sie sie ignorieren.
E Web.config
Diese Datei konfiguriert Ihre Applikation. Der Einsatz ist
auf Live-Servern notwendig. Auf einem Entwicklungsrech-
ner hat die Verwendung mehr experimentellen Charakter.
E WebForm1.aspx
Damit Sie gleich loslegen kCnnen, hat Visual Studio .NET
gleich eine Web Form erzeugt. Wenn Sie diese Cffnen und
(F7) dr"cken, gelangen Sie in die dazu erzeugte Code-
Datei.
E Assemblyname
Name der Assembly, die dieses Projekt erzeugen wird.
E Standardnamespace
Der Namensraum, der beim Erzeugen verwendet werden soll.
Sandini Bib
berblick :ber die IDE 101
E Startobjekt
Dieser Eintrag gibt das Objekt an, mit dem der Debugger star-
ten soll.
E Erstellen
Legen Sie hier den Ausgabepfad f"r die Assembly fest. Der
Standardpfad ist bin\.
E Debuggen
Achten Sie hier darauf, dass die Option ASP.NET-Debuggen
aktivieren w>hrend der Entwicklungsphase aktiviert ist.
Wichtig ist auch die Startaktion, die immer auf Projekt star-
ten stehen sollte. Außerdem ist die Startseite festzulegen. F"r
die Buchprojekte bietet sich default.aspx an, ein Programm, das
alle aspx-Seiten zur Ausf"hrung und zur Betrachtung des
Quelltextes anbietet.
Sie sehen nun die Designer-Oberfl>che vor sich. Eine erste, noch
leere Webform wurde bereits angelegt und im entsprechenden
Verzeichnis des IIS verCffentlicht. Dar"ber hinaus befinden sich
dort bereits eine ganze Anzahl weiterer Dateien.
F"r den Beginn wollen wir in dieser leeren Webform nur ein Label
mit etwas Text definieren, welches dann mit Hilfe von ASP.NET
dynamisch mit Inhalt gef"llt wird. Klicken Sie auf der Toolbox
am rechten Rand auf Label. Ziehen Sie den Eintrag aus dieser
Leiste auf die noch leere Webform oder ziehen Sie einfach, nach-
dem der Mauszeiger zu einem Plus-Zeichen geworden ist, auf der
Fl>che ein Rechteck in der gew"nschten GrCße. Nun sollte Ihr
Bildschirm etwa so aussehen, wie in Abbildung 2.10 gezeigt.
Was VS.NET Obwohl Sie noch keinen Code geschrieben haben, finden Sie hier
erzeugt hat schon einige Zeilen davon vor. Gehen Sie zu der Zeile, die durch
den Kommentar ' Hier Benutzercode... gekennzeichnet ist. F"gen
Sie direkt danach oder davor eine neue Zeile ein und geben Sie
den folgenden Code ein:
Beachten Sie, dass unter VB.NET, anders als beispielsweise unter C#, ei-
t ne Anweisung immer vollst:ndig auf einer Zeile erscheinen muss. Sie
k5nnen fBr eine bessere Rbersichtlichkeit die Zeilen im Editor trennen,
indem Sie am Zeilenende vor dem Umbruch einen Unterstrich, gefBhrt
von einem Leerzeichen, einsetzen.
Label1 ist der Bezeichner des von Ihnen angelegten Objekts. Sie
kCnnen das im Eigenschaften-Fenster des Labels "berpr"fen,
wenn Sie dort den Eintrag (ID) aufsuchen. Zwischen der Desig-
ner- und der Codesicht kCnnen Sie "ber die Registerkarten am
oberen Bildschirmrand, jedoch unterhalb der Symbolleisten, um-
schalten. Unter der Registerkarte Webform1.aspx finden Sie den
Designer, unter Webform1.aspx.vb den Code im Code-Editor. Hier
Sandini Bib
Erste Schritte in der Programmierung 105
An dieser Stelle soll im Vorgriff auf die Beschreibung des Debuggers die
Bedeutung der Tastenkombinationen (Strg)+(F5) bzw. (F5) verraten
werden. Mit (F5) starten Sie das Programm mit dem Debugger. Wenn
Sie dagegen (Strg)+(F5) verwenden, wird es nur gestartet. Gespeichert
und kompiliert wird es nat&rlich in jedem Fall automatisch.
Zuerst erfolgt die Definition der Klasse WebForm1. Diese wurde mit Wie es
dem Anlegen des Projekts automatisch von System.Web.UI.Page funktioniert
abgeleitet (Schl&sselwort Inherits). Sie muss selbst wiederum als
Public deklariert sein, damit sie direkt ausgef&hrt werden kann.
Unter anderem finden Sie im Abschnitt 4.3, »Objektorientierte
Programmierung« ab Seite 176 dazu weitere Informationen.
E Drei Label-Steuerelemente
E Zwei TextBox-Steuerelemente
E Ein Button-Steuerelement
Sandini Bib
Erste Schritte in der Programmierung 107
Beschriften Sie die ersten beiden Label mit Name und Vorname
&ber deren jeweiliges Eigenschaften-Fenster (Funktionstaste
(F4), Eigenschaft Text). Geben Sie dem Button auf die gleiche
Weise die Aufschrift Absenden.
End Sub
#End Region
End Sub
End Class
Ein erster Start Wenn Sie jetzt die Funktionstaste (F5) dr&cken, werden Sie fest-
stellen, dass das Programm aufgerufen wird und grunds2tzlich
funktioniert.
beim Klick auf den Button an den IIS gesendet. Das betrifft auch
den Inhalt der beiden eventuell gef&llten Eingabefelder. Der In-
halt wird zwar noch nicht weiter durch das Programm verarbei-
tet, beim Zur&cksenden des Formulars an den Browser werden
diese Werte aber wieder &bergeben. So kommt es, dass Sie nach
dem Absenden nicht wieder ein geleertes Formular vorfinden,
wie dies mit der klassischen HTML-Formularprogrammierung
zwangsl2ufig der Fall ist.
Damit bei einem Klick auf Absenden der Inhalt der beiden Felder
verarbeitet werden kann, m&ssen Sie die Routine zur Behandlung
des Klick-Ereignisses entsprechend erweitern. F&hren Sie dazu im
Designer einen Doppelklick auf den Button aus. Die Ansicht
schaltet daraufhin in den Code und Sie finden die folgenden neu-
en Zeilen vor:
End Sub
Wenn Sie jetzt das Programm starten, sollte nach dem Klick auf
Absenden das Eingabeformular etwa wie folgt aussehen (siehe
Abbildung 2.15).
Sandini Bib
110 2 Visual Studio .NET
Abbildung 2.15: Das fertige Formular nach dem Ausf(llen und Absenden
Wie es Im Unterschied zum ersten Beispiel, bei dem nur eine Website mit
funktioniert einem dynamischen Inhalt generiert wird, muss diese Site auf eine
Benutzeraktion reagieren. Dazu wird mit ASP.NET eine Ereignis-
behandlung durchgef&hrt, welche der Code Designer automatisch
implementiert. F&r ein besseres Verst2ndnis stellt die folgende
Grafik die Prozesse dar, die dabei ablaufen:
Den Klick Beim Klick auf die Schaltfl2che mit der Bezeichnung Button1 wird
behandeln ein Ereignis Button1.Click ausgel/st. Dieses Ereignis wird durch
die Methode Button1_Click behandelt.
Was geschieht Interessant ist f&r dieses Beispiel, zu untersuchen, wie die
im HTML? Kommunikation zwischen Client (Browser) und dem Server
(ASP.NET) abl2uft. Wenn Sie sich im Browser-Fenster den HTML-
Sandini Bib
Erste Schritte in der Programmierung 111
Code ansehen, werden Sie feststellen, dass hier nichts direkt auf
Ereignisse hindeutet.
1 Diesen k/nnen Sie auch selbst deklarieren, um sie beispielsweise &ber Ja-
vaScript anzusprechen. Darauf wird im vorliegenden Buch nicht weiter ein-
gegangen. Wenn Sie dies nicht vorhaben, sollten Sie den id-Parameter gene-
rell unver2ndert lassen.
Sandini Bib
112 2 Visual Studio .NET
Ihnen sollte bewusst sein, dass der Inhalt der Eingabefelder nur
deshalb erhalten geblieben ist, weil der Browser ein entsprechend
ausgef&lltes Formular vom Server zur&ck erhalten hat. ASP.NET
hat dazu den Wert von __VIEWSTATE ausgewertet und daraus die
Inhalte und Attribute der Felder des Formulars neu gesetzt.
End Sub
Sandini Bib
Erste Schritte in der Programmierung 113
Label1.ForeColor = Color.Black
Warum wird das Label wieder schwarz, wenn sich der Inhalt des Abarbeitungs-
Feldes nicht ge2ndert hat? Um dies zu verstehen, sollten Sie sich reihenfolge
die Abarbeitungsreihenfolge unter ASP.NET vor Augen f&hren:
2. Ist die Seite soweit fertig, erfolgt der Aufruf der Page_Load-
Methode. In diesem Beispiel wird damit die Farbe des Labels
explizit auf Color.Black gesetzt.
3. Nach Page_Load werden alle weiteren Ereignisse behandelt.
Wird dabei &ber die Methode TextBox1.TextChanged erkannt,
dass sich der Inhalt von TextBox1 ge2ndert hat, erfolgt der Auf-
ruf von TextBox1_TextChanged und Label1 wird auf Color.Red ge-
setzt.
Abbildung 2.18: Auswahl des Jet-Providers f(r den Zugriff auf Access
Sollen alle Felder ausgew2hlt werden, k/nnen Sie auch die ers-
te Option * (Alle Spalten) setzen. Da Sternchen steht f&r alle
Felder (intern wird eine SQL-Anweisung erzeugt).
Nach einem Klick auf OK und Fertigstellen wird der neue Da-
tenadapter erzeugt. Unterhalb der Webform-Arbeitsfl2che werden
dann diese beiden Objekte angezeigt:
E oleDbDataAdapter1
Dies ist der Datenadapter, den Sie soeben erzeugt haben.
E oleDbConnection1
Diese Datenverbindung stellt die Verbindung zur Access-
Datenbank Shop.mdb her und wird vom Datenadapter benutzt.
DataSet erzeugen Um ein DataSet zu erzeugen, gehen Sie wie folgt vor:
1. Klicken Sie im Designer mit der rechten Maustaste auf den an-
gelegten DataAdapter und w2hlen Sie aus dem dann erscheinen-
den Kontextmen& den Punkt DataSet generieren.
Sandini Bib
Erste Schritte in der Programmierung 119
Wenn Sie nun das Programm starten, werden Sie feststellen, dass
zun2chst nur eine leere Website erzeugt wird. Das liegt daran,
weil das DataSet noch nicht mit Daten gef&llt worden ist. Dies
m&ssen Sie per Hand in der Methode Page_Load eintragen. F&gen
Sie hier die folgenden zwei Zeilen ein:
oleDbDataAdapter1.Fill(dataSet11)
DataGrid1.DataBind()
Mit der ersten Anweisung f&llen Sie das DataSet &ber den Daten-
adapter mit Daten. Gezeigt wird hier die einfachste Art des Auf-
rufs. Bei komplexeren DataSets mit mehr als einer Tabelle k/nnen
Sie als zweite Option die gew&nschte Tabelle angeben.
Wenn Sie nun das Programm starten, sollten Sie in etwa die fol-
gende Ausgabe im Browser sehen:
Sandini Bib
Erste Schritte in der Programmierung 121
1. Name
2. Straße
3. Postleitzahl
4. Ort
Dies sind auch die richtigen Bezeichner der Tabellenspalten –
schließlich sieht es nicht besonders sch/n aus, wenn nur Kurz-
bezeichner wie str oder plz erscheinen.
Eigenschaften- Sie richten die Struktur und das Aussehen des DataGrids im Ei-
Generator genschaften-Generator ein. Diesen starten Sie, wenn Sie auf das
DataGrid im Webforms-Designer mit der rechten Maustaste kli-
cken und aus dem Kontextmen& den gleichnamigen Eintrag w2h-
len.
F&r das Funktionieren dieses Beispiels ist es wichtig, dass Sie als Footer-
text f&r jede Spalte den exakten Spaltennamen der Datenbank-Tabelle
Adressen eintragen. Dies ist genau genommen ein Trick, damit f&r die
manuell zu programmierende Aktualisierung der Datenbank nicht zu vie-
le Codezeilen ben3tigt werden und das Beispiel zu komplex wird.
Schaltflchen Jetzt fehlen noch die Schaltfl2chen, &ber die der Besucher der
hinzuf&gen Website in den Editiermodus f&r die Zeile gelangen kann. Diese
finden Sie weiter unten in der Liste unter Verfgbare Spalten.
W2hlen Sie dazu unter Schaltfl+chenspalte den Eintrag Bear-
beiten, Aktualisieren, Abbrechen aus. Es erscheint dann pro
Spalte eine Schaltfl2che Bearbeiten.
Im zweiten Schritt erstellen Sie die Methoden f&r die Behandlung Schritt 2:
der Ereignisse, die beim Klick des Benutzers auf die Schaltfl2chen Ereignisbehand-
lungs-Methoden
im DataGrid ausgel/st werden. Gehen Sie dazu wie schon seit vie-
len Jahren unter Visual Basic &blich in den Code-Editor zur&ck
und dann wie folgt vor:
1. W2hlen Sie im Objekt-Inspektor das entsprechende Datagrid-
Objekt aus.
2. W2hlen Sie dann nacheinander die Ereignisse CancelCommand,
EditCommand und UpdateCommand aus.
DataGrid1.EditItemIndex = e.Item.ItemIndex
DataGrid1.DataBind()
End Sub
Dim i As Integer
Dim tbControl As TextBox
Dim colName As String
For i = 0 To e.Item.Cells.Count - 2
tbControl = CType(e.Item.Cells(i).Controls(0), TextBox)
colName = DataGrid1.Columns(i).FooterText
DataSet11.Tables("Adressen") É
.Rows(e.Item.ItemIndex)(colName) É
= tbControl.Text
Next
OleDbDataAdapter1.Update(DataSet11)
DataGrid1.EditItemIndex = -1
DataGrid1.DataBind()
End Sub
DataGrid1.EditItemIndex = -1
DataGrid1.DataBind()
End Sub
Listing 2.3: Die fertigen Ereignisbehandlungs-Methoden f(r das Beispiel
(f(r den Druck etwas formatiert)
Wie es Bis auf die Methode f&r die Behandlung des Update-Ereignisses
funktioniert sind die manuell zu erstellenden Codebestandteile sehr einfach.
Der in allen drei Methoden vorhandene Aufruf von DataGrid1.
DataBind() baut das DataGrid neu auf und &bergibt es an die Seite.
Abh2ngig davon, welche Zeile selektiert ist, wird diese zum Edi-
tieren angeboten. In der Methode DataGrid1_CancelCommand wird
Sandini Bib
Erste Schritte in der Programmierung 127
dataSet11.Tables("Adressen").Rows(e.Item.ItemIndex)(1)
2.4.1 Fehlerarten
Bevor Sie sich dem professionellen Umgang mit dem Debugger
widmen, sollte Ihnen klar sein, welche Art Fehler prinzipiell auf-
treten k/nnen und ob, beziehungsweise wie, der Debugger zu de-
ren Behebung gute Dienste zu leisten vermag.
Syntaxfehler
Mit Syntaxfehlern sind alle Fehler gemeint, die bereits im Code
Designer erkannt werden und einen Start beziehungsweise das
Kompilieren des Programms verhindern. Im Visual Studio wer-
den Syntaxfehler mit einer blauen Schlangenlinie gekennzeichnet.
Abbildung 2.32: Ein Blick in die Aufgabenliste, Kategorie Aufgaben oder Buildfehler, hilft
immer.
Compilerfehler
Auch wenn syntaktisch alles richtig ist, kann es zu einem Compi-
lerfehler kommen. So k/nnen Sie beispielsweise eigene Metho-
denbezeichner verwenden, ohne dass das hilfreiche Intellisense im
Studio daran Anstoß nimmt. Wenn Sie dann allerdings vergessen,
Ihre Methode auch zu deklarieren, wird zwangsl2ufig der Compi-
ler dar&ber stolpern. Im Studio wird eine Fehlermeldung wie in
nachfolgender Abbildung gezeigt erscheinen, wenn Sie ver-
suchen, das Programm zu starten.
Details nur unter Im Fenster des Browsers bekommen Sie ebenfalls detaillierte In-
localhost formationen zur Art des Fehlers und dem vermutlichen Ort der
Ursache. 3ber weitere Links am unteren Ende der Ausgabe k/n-
Sandini Bib
Fehlersuche und Debugging 131
Laufzeitfehler
Kann ein Programm kompiliert werden, heißt das noch lange Schwer zu finden:
nicht, dass es auch stets stabil und fehlerfrei funktioniert. Fehler, Debugger helfen
die jetzt, w2hrend der normalen Laufzeit auftreten, werden des-
halb Laufzeitfehler genannt. Sie sind besonders schwer zu lokalisie-
ren. Damit schl2gt die Stunde der Debugger. Dieser kann bei-
spielsweise ein Programm schrittweise abarbeiten oder Ihnen
Informationen &ber den Inhalt von Variablen liefern. Da selten
das gesamte Programm Schritt f&r Schritt abgearbeitet werden
soll, k/nnen Sie so genannte Haltepunkte definieren, ab denen der
Debugger mit der interaktiven Schrittfolge durch den Code begin-
nen soll.
Damit ein Programm mit der Hilfe eines Debuggers bearbeitet Voraussetzungen
werden kann, muss der Compiler zus2tzlichen Code, auch Debug- zum Debuggen
E Global im Studio
Im Studio finden Sie in der Standard-Symbolleiste ein Aus-
wahlmen&, &ber welches Sie einfach und schnell zwischen der
Verarbeitung mit und ohne Debugging umschalten k/nnen.
Wichtig ist, dass Sie f&r das Debuggen von ASP.NET-Code das
in Abbildung 2.37 markierte Kontrollk2stchen aktivieren. Zu
den weiteren Optionen, die beispielsweise das Debuggen von
ASP-Anwendungen oder nicht verwaltetem Code betreffen,
finden Sie weiterf&hrende Informationen in der Online-Hilfe.
Sandini Bib
134 2 Visual Studio .NET
Haltepunkte setzen
Klick in Rahmen Um einen Haltepunkt zu setzen, ab dem der Debugger mit der
schrittweisen Abarbeitung des Codes beginnen soll, klicken Sie
einfach in den grauen Rahmen links neben dem Code an die ge-
w&nschte Stelle. Der Debugger wird dann genau vor der markier-
ten Zeile einsetzen und das Programm stoppen.
E Gehen Sie mit dem Cursor zu der gew&nschten Stelle und be-
t2tigen Sie die Tastenkombination (Strg)+(B). Es erscheint ein
Dialogfenster, in welchem Sie weitere Optionen zum Halte-
punkt definieren k/nnen (siehe weiter unten im Text). Aller-
dings m&ssen Sie bei dieser Art der Haltepunkt-Definition alle
relevanten Einstellungen wie die genaue Position im Quelltext
erst noch mitteilen.
Sandini Bib
Fehlersuche und Debugging 135
Zu einem Haltepunkt k/nnen Sie weitere Optionen einstellen und Weitere Optionen
damit die Verarbeitung durch den Compiler beeinflussen. F&r ei-
nen bestehenden Haltepunkt erhalten Sie dieses Fenster &ber ei-
nen Klick mit der rechten Maustaste auf die Markierung im Quell-
text und die Wahl des Punktes Haltepunkteigenschaften.
E Einzelschritt
(F11) 3ber einen Druck auf die Funktionstaste (F11) bewegen Sie
sich schrittweise durch das Programm, beginnend beim ersten
Haltepunkt. Dabei wird auch einzelschrittweise in alle auf-
gerufenen Methoden hinein verzweigt.
E Prozedurschritt
(F10) 3ber (F10) gehen Sie schrittweise durch die Methode, begin-
nend am ersten Haltepunkt. In Methoden, die von hier aus
aufgerufen werden, wird nicht verzweigt. Diese werden wie
ein einziger Schritt behandelt und komplett abgearbeitet. Da-
mit sparen Sie sich, Code zu debuggen, der nichts mit Ihrem
Problem zu tun hat.
Sandini Bib
Fehlersuche und Debugging 137
E Schnell&berwachung
3ber des Hauptmen& Debuggen | Schnellberwachung (Strg+Alt+Q)
oder die Tastenkombination (Strg)+(Alt)+(Q) /ffnen Sie das
Dialogfenster f&r die Konfiguration des 3berwachungsfens-
ters. Klicken Sie hier auf Hinzufgen, um bestimmte Werte
zu 3berwachen. Das eigentliche 3berwachungsfenster er-
scheint erst nach Abschluss der Konfiguration – standard-
m2ßig am unteren Bildschirmrand – und gibt dann die Werte
der zu &berwachenden Objekte aus. Sie k/nnen in dieses 3ber-
wachungsfenster auch direkt die Werte eingeben.
E Befehlsfenster
(Strg+Alt+A) Das Fenster f&r die Schnell&berwachung zeigt zwar alle ge-
w&nschten Werte an, kann aber ebenso schnell un&bersichtlich
werden. F&r die einfache Einsicht in bestimmte Werte kann
deshalb das Befehlsfenster erg2nzend oder alternativ interes-
sant sein. Nffnen Sie dieses &ber die Tastenkombination
(Strg)+(Alt)+(A) oder das Men& Ansicht | Andere Fenster |
Befehlsfenster.
Debuggerprobleme
Manchmal hat der Debugger selbst Probleme und will nicht star-
ten. Generell sollten Sie auf Folgendes achten:
E Wenn Sie die Maschine mit dem »IIS Lock Down Tool« ge-
sch&tzt haben, erg2nzen Sie in der Konfigurationsdatei
urlscan.ini Folgendes:
Im Abschnitt [AllowVerbs], f&gen Sie DEBUG hinzu. Unter
[AllowExtensions] erg2nzen Sie .aspx und .asmx. Der IIS muss
danach neu gestartet werden. Geben Sie dazu an der Eingabe-
aufforderung C:\>iisreset ein.
E Installieren Sie ASP.NET neu (nicht Visual Studio .NET), in-
dem Sie Folgendes an der Visual Studio .NET-Befehlsaufforde-
rung eingeben:
C:\>aspnet_regiis.exe -i
Anschließend starten Sie den IIS neu, indem Sie an der Ein-
gabeaufforderung Folgendes eingeben:
C:\>iisreset
Hilfe aus dem Wenn alles nicht hilft, lesen Sie folgendes Dokument (englisch)
Internet sorgf2ltig:
http://www.gotdotnet.com/team/csharp/Information/Whitepapers/
howtosolvedebuggerproblems.doc
Option Strict Lassen Sie den Parameter allerdings weg, nimmt der Compiler Off
an. Neben der Deklaration ist auch die Angabe des Datentyps er-
forderlich. Bedingt durch das dem .NET-Framework zugrunde
liegende Common Type System, das allen Sprachen einheitliche
Datentypen bereitstellt, kommt der exakten Typdeklaration eine
große Bedeutung zu. Es gibt deshalb keinen allgemeinen Daten-
typ Variant mehr. In manchen F2llen wird daf&r der Typ Object
verwendet. Die Verarbeitung erfolgt aber intern anders, sodass
dies nicht als Austausch eines Schl&sselwortes zu verstehen ist.
VB.NET kann bei elementaren Datentypen erkennen, was gemeint
ist, ohne dass das entsprechende Schl&sselwort explizit geschrie-
ben wird. M/chten Sie das nicht, hilft Option Strict On. Etwas frei-
z&giger programmiert es sich mit Option Strict Off.
Dim i As Integer
Dim i, j, k As Long
Sandini Bib
@berblick f(r Umsteiger von VBScript 145
Dim m As Integer = 1
Dim i As Integer = 23
Dim s As String = CType(i, String)
Genderte Sprachanweisungen
If Einige Vereinfachungen in der Notation fielen der 3berarbeitung
zum Opfer. So ist die verk&rzte Schreibweise von If Then nicht
mehr erlaubt. Jedes If verlangt zwingend sein End If.
If i = 23 Then
' tu was
End If
Allerdings f2llt das in der Praxis kaum auf, wenn Sie Visual
Studio.NET als Editor verwenden. Tippen Sie nach If i = 23 auf
(Enter), wird der komplette Block durch ein Editormakro erzeugt.
IIf Neu ist eine Kombinationsanweisung IIf, die den If-Befehl ver-
k&rzt, aber leider sehr langsam ist:
While Die While-Anweisung ist etwas logischer, statt Wend wird sie nun
mit End While geschlossen und entspricht damit einem etwas ver-
st2ndlicheren Schema. F&r die anderen Schleifen For (endet immer
noch mit Next statt mit End For) und Do (endet mit Loop und nicht
mit End Do) gilt das nicht.
Optimierungsstrategien
Da VB.NET auf einem Compiler basiert, k/nnen bei der Verarbei-
tung Optimierungen vorgenommen werden. Das passiert auch
fleißig, ohne dass Sie es bemerken. Sie m&ssen daran aber in man-
chen F2llen denken, beispielsweise bei folgendem Konstrukt:
Neu: OrElse, Hier wird zuerst, wie erwartet, Function1 aufgerufen. Ergibt der
AndAlso Ausdruck auf der linken Seite danach True, kann der gesamte
Ausdruck aufgrund der Oder-Verkn&pfung nur noch True sein.
Der Compiler optimiert die rechte Seite dann einfach weg, Func-
tion2 wird nicht ausgef&hrt. Das kann zu ungl&cklichen Seiten-
effekten f&hren, wenn Sie in Function2 irgendeine Aktion starten,
die unabh2ngig vom R&ckgabewert notwendig ist, beispielsweise
eine Datenbankverbindung /ffnen oder schließen. Zur L/sung
des Problems gibt es neue Boolesche Operatoren mit den Namen
OrElse und AndAlso. Mehr dazu finden Sie in Abschnitt »Bedingun-
gen« ab Seite 165.
Sandini Bib
@berblick f(r Umsteiger von VBScript 147
Misslingt hier der linke Teil, bricht der Optimierer ab. Das verhin-
dert, dass der rechte Teil in einem Laufzeitfehler l2uft. So kann
man die Optimierung ausnutzen, um kompakteren Code zu
schreiben.
Operatoren
Neues gibt es auch bei origin2ren Operatoren. So k/nnen Zeichen-
ketten außer mit & auch mit + verkn&pft werden. In allen F2llen
sind Leerzeichen zwischen den Operanden und dem Operator er-
forderlich. Visual Studio .NET f> diese beim Tippen auto-
matisch ein.
Variant Der Datentyp Variant ist nicht mehr vorhanden. Stattdessen wird
Object eingesetzt. Allerdings verh2lt sich Object in vielen F2llen
anders und verf> &ber neue Eigenschaften.
3.2.2 Funktionen
Viele Funktionen, die VB 6 standardm2ßig bot, sind nun Teil des
Frameworks. Deshalb 2ndert sich in vielen F2llen sowohl der Na-
me als auch die Syntax. Die Klassen aus dem Framework sind in
Namensr2umen organisiert. Einige werden standardm2ßig immer
eingebunden, wenn Sie mit Visual Studio .NET arbeiten. Deshalb
verh2lt sich VB.NET oft 2hnlich. Tats2chlich ist die innere Funk-
tionsweise anders.
Mathematische Funktionen
Die mathematischen Funktionen sind im Namensraum System ent-
halten. Die folgende Tabelle zeigt die alten und neuen Namen:
Wenn der Zugriff auf Namensraum und Klasse nicht explizit mit
Imports System.Math erfolgt, schreiben Sie System.Math.<Method>.
Zeichenketten
Auch die Zeichenketten finden sich komplett im Framework wie-
der, umfangreicher und leistungsf2higer als in VB 6. Das Laufzeit-
modul sichert jedoch auch hier eine weitgehende Kompatibilit2t,
sodass VB 6-Code leicht verwendet werden kann.
VB 6-Funktion VB.NET-Methode
LTrim String.TrimStart
Trim String.Trim
RTrim String.TrimEnd
Left String.Substring
Right String.Substring
Len String.Length
Mid String.Substring
Join String.Join
Split String.Split
Beachten Sie, dass die Klasse String weit mehr Methoden und Ei-
genschaften liefert.
Dann folgt die HTML-Seite, die Ihr Browser anzeigen soll. Der
Code selbst ist in ASP-Tags <% %> eingebettet. Dieses Prinzip hat
sich gegen&ber ASP nicht ge2ndert – es sind nur weitere, alternati-
ve Wege hinzugekommen, unter anderem die so genannte Daten-
bindung. Dies wird ausf&hrlich in Abschnitt 6.6.2, »Aufbau der
Vorlagen in Daten-Steuerelementen« ab Seite 570 diskutiert wer-
den.
Dateierweiterung Vergessen Sie nun nicht, das Programm mit der Dateierweiterung
.aspx zu speichern. F&hren Sie es im Browser aus, wobei auf einem
Entwicklungssystem der Servername »localhost« verwendet wird
(»http://localhost/pfad/dateiname.aspx«).
Wenn das gezeigte Bild auch bei Ihnen zu sehen ist, k/nnen Sie al-
le nachfolgenden Beispiele ausf&hren und bequem VB.NET und
ASP.NET lernen.
3.4 Spracheinf2hrung
Dieser Abschnitt enth2lt eine kompakte Spracheinf&hrung, die
wenig Vorwissen voraussetzt und auf den Bedarf dieses Buches
»zurechtgestutzt« wurde. Aus Platzgr&nden kann VB.NET nicht
umfassend behandelt werden. Konsultieren Sie bei Bedarf die On-
line-Hilfe und die MSDN-Bibliothek, die umfassende und voll-
st2ndige Informationen bietet. Eine Unterscheidung zwischen
»Neu« (VB.NET) und »Alt« (VB 6) wird in diesem Abschnitt nicht
mehr vorgenommen.
Objekt.Methode()
Variablendeklarationen
Beispiele f&r typische Variablendeklarationen finden Sie nachfol-
gend:
Hier wird deutlich, dass es nicht ausreicht die Variable als solche,
also deren Namen, festzulegen. Sie m&ssen immer einen Datentyp
angeben. Der n2chste Abschnitt geht darauf detailliert ein.
An der Beschreibung des letzten Typs, System.Object, wird klar, Bedeutung des
dass allen Typen Objekte zugrunde liegen. Auf Objekte wurde Typs Object
Sandini Bib
156 3 Einf(hrung in Visual Basic .NET
Methode Beschreibung
Equals Vergleicht zwei Objekte auf Gleichheit
GetHashCode Gibt einen Identifikator des Objekts zur2ck. Hashes sind spe-
zielle Arten von Aufzhlungen. Werden Variablen als Schl2ssel
verwendet, kBnnen die Elemente anhand der Hashcodes iden-
tifiziert werden.
GetType Gibt ein Typ-Objekt zur2ck, mit dem der Typ selbst unter-
sucht werden kann. Diese Art des Zugriffs auf interne
Definitionen wird Reflektion genannt.
ToString Mit dieser Methode wird der Typ in eine Zeichenkette umge-
wandelt. Sie haben dies bereits im ersten Beispiel verwendet.
Wenn Sie Variablen deklarieren, m&ssen Sie nur dann das Frame-
work direkt verwenden, wenn der Typ in VB.NET nicht direkt
verf&gbar ist. Die Deklaration aus dem ersten Beispiel k/nnte
auch folgendermaßen aussehen:
Dim hw As System.String = "Hello World"
Hier wird auf Long erkannt, weil die Zahl keine Kommastelle ent-
h2lt. Schreibt man ».0« am Ende, wird dagegen auf Double erkannt,
was wiederum falsch ist. Letztlich hilft nur das Literalzeichen »D«
als Suffix des Zahlliterals.
Umwandlungsfunktion Zieldatentyp
CBool Boolesch
CByte Byte
CChar Char
CDbl Double
CDec Decimal
CInt Integer
CLng Long
CObj Ojbect
CShort Short
CSng Single
CStr String
CDate Date
Der zweite Parameter ist der Bezeichner des Typs bzw. einer Klas-
se des Frameworks, gegebenenfalls vollst2ndig qualifiziert durch
Angabe des Namensraumes:
Funktion Bedeutung
Hex Dezimalzahl als Hexadezimale Form ohne Prfix, Typ
String
Oct Dezimalzahl als oktale Form ohne Prfix, Typ String
Str Zahl als Zeichenkette
Val Zeichenkette als Zahl. Leerzeichen werden entfernt,
Prfixe beachtet.
Chr, ChrW Ermittelt den Zeichencode zu einem Zeichen, »W«
steht f2r Unicode.
Asc, AscW Ermittelt das Zeichen zu einem Zeichencode, »W« steht
f2r Unicode.
Benutzerdefinierte Datentypen
Manchmal kann es sinnvoll sein, eigene Datentypen zu deklarie-
ren. Dazu dient die Structure-Anweisung. Da Datentypen in .NET
immer Objekte sind und diese aus Klassen stammen, verf&gen sie
auch &ber Eigenschaften und Methoden. Die Nutzung der Struk-
turen setzt deshalb Kenntnisse der objektorientierten Program-
mierung voraus. Abschnitt 3.4.8, »Namensr2ume und Klassen« ab
Seite 176 geht auf dieses Thema ausf&hrlich ein.
Logische Werte
Logische Werte Logische Werte werden auch als Boolesch bezeichnet. Diese haben
zwei m/gliche Zust2nde: Wahr und Falsch; in VB.NET durch die
Schl&sselw/rter True und False gekennzeichnet.
Sandini Bib
Spracheinf(hrung 161
3.4.3 Konstanten
Konstanten verhalten sich wie Variablen, deren Inhalt sich w2h-
rend der Laufzeit nicht 2ndern kann. Definiert werden sie mit
dem Schl&sselwort Const:
Vordefinierte Konstanten
Bei der Ausgabe von Text in Dateien oder im Browser sind
manchmal spezielle Codes notwendig, beispielsweise f&r Zeilen-
umbr&che. VB.NET bietet hier eine Auswahl vordefinierter Werte:
3.4.4 Kommentare
Kommentare in VB.NET beginnen immer mit einem Kommentar-
zeichen oder dem Schl&sselwort Rem. Sie enden am Zeilenende:
3.4.5 Operatoren
In Programmen wird viel gerechnet. VB.NET kennt die &blichen
Operatoren und bietet wenig &berraschendes bei der Schreibwei-
se. Zwei haben Sie bereits kennengelernt: Die Zuweisung mit »=«
und die Verkettung von Zeichenketten mit »+«. Daneben ist auch
der Verkettungsoperator »&« einsetzbar, der diese Aufgabe in
VBScript und VB 6 exklusiv &bernahm.
Arithmetische VB.NET kennt die elementaren arithmetischen Operatoren:
Operatoren
x + y ' Addition
x - y ' Subtraktion
x * y ' Multiplikation
x / y ' Division mit dem Ergebnistyp Double
x \ y ' Division mit dem Ergebnistyp Integer
x Mod y ' Modulus (Rest der Ganzzahldivision)
y
x ^ y ' Potenz x
Beachten Sie außerdem, dass die Abarbeitung innerhalb der Seite zwar
m3glich, aber konzeptionell nicht gewollt ist. F&r dieses Beispiel wurde
diese Variante gew+hlt, um den Code so weit wie m3glich zu verein-
fachen.
<%
Dim rd As String = "<td width=""100"">A</td> É
<td width=""100"">B</td> É
<td width=""100"">C</td>"
Response.Write("<table border=""0"" cellpadding=""4"">")
Response.Write("<th>Spalte A</th><th>Spalte B</th><th>Spalte
C</th>")
Dim i As Integer
For i = 0 To 10
If i Mod 2 = 0 Then
Response.Write("<tr bgcolor=""Gray"">" & rd & "</tr>")
Else
Response.Write("<tr bgcolor=""White"">" & rd & "</tr>")
End If
Next
%>
Listing 3.2: Verwendung des Modulus-Operators (VbOperatorModulus.aspx)
Bitoperatoren Wenn Variablen Werte enthalten, die sich in Byte- oder Bitform
darstellen lassen, k/nnen Manipulationen mit Bitoperatoren sinn-
voll sein. Als Datentyp kommt beispielsweise byte in Betracht. Der
Operator And f&hrt eine bin2re UND-Verkn&pfung durch, Or steht
f&r eine ODER-Verkn&pfung, w2hrend Not den Bitwert negiert.
Das exklusive Oder (Xor) ist immer dann 1, wenn einer der beiden
Operatoren 1 ist (also exklusiv), nicht aber beide. Die Operatoren
entsprechen der Booleschen Algebra. Das Verhalten kann der
Auflistung in der folgenden Tabelle entnommen werden.
Das folgende Beispiel zeigt das Prinzip. Denken Sie dabei an die
interne Darstellung der Zahl 3 (00000011) bzw. 5 (00000101). Der
gew2hlte Datentyp Byte arbeitet ohne Vorzeichen.
<%
Dim bNull As Byte = 3
Dim bEins As Byte = 5
Response.Write ((bEins and bNull).ToString())
Sandini Bib
Spracheinf(hrung 165
Response.Write ("<br>")
Response.Write ((bEins or bNull).ToString())
Response.Write ("<br>")
Response.Write ((Not bEins).ToString())
Response.Write ("<br>")
Response.Write ((Not bNull).ToString())
%>
Listing 3.3: Testprogramm f(r die Bitoperatoren (VbOperator8Bit.aspx)
3.4.6 Verzweigungen
Verzweigungen sind ein elementarer Bestandteil auch kleiner Pro-
gramme. Dabei wird der ein oder andere Programmteil in Abh2n-
gigkeit von einer Bedingung ausgef&hrt.
Bedingungen
Bedingungen sind das bestimmende Element zur Steuerung von
Verzweigungen. Es gibt praktisch kaum ein Programm, das v/llig
ohne die Steuerung mit Bedingungen auskommt. Das Programm
Sandini Bib
166 3 Einf(hrung in Visual Basic .NET
Optimierende VB.NET arbeitet bei der Abarbeitung mit einer einfachen internen
Operatoren Optimierung. Wenn bei einem UND-Vergleich der erste Operator
AndAlso, OrElse
False ist, kann der Ausdruck nur False werden, unabh2ngig vom
Zustand des zweiten. Entsprechend wird der Ausdruck einer
ODER-Verkn&pfung True, wenn der erste Operator True ist. Auch
hier ist es nicht zwingend notwendig, den zweiten anzugeben.
Dieses Verhalten kann in der Praxis unerw&nscht sein. Wenn der
zweite Operand ein Methodenaufruf ist, wird die Methode m/gli-
cherweise niemals aufgerufen. Dies kann aber notwendig sein,
wenn die Methode neben dem R&ckgabewert auch andere Aktio-
nen ausf&hrt. Deshalb gibt es zwei weitere Operatoren, die die
Optimierung unterdr&cken und den rechten Teil eines Ausdrucks
immer auswerten:
Operator Bedeutung
= Gleichheit
<> Ungleichheit
< Kleiner als
>= GrBßer als oder gleich
<= Kleiner als oder gleich
> GrBßer als
If Bedingung Then
Anweisung-1
Anweisung-2
End If
Das Beispiel ist sicher primitiv. Praktisch kann immer nur eine
der Alternativen erf&llt sein, denn tag enth2lt einen ganz bestimm-
ten Wert. Allerdings besteht auch die – zumindest theoretische
Chance – dass keine der Bedingungen zutrifft. Diesen Zustand ab-
zufangen, ist mit If-Anweisungen dieser Art schon schwieriger.
Im Abschnitt »Mehrfachbedingungen mit Select Case« ab Seite 169
finden Sie eine elegantere Alternative.
Else Wenn man weiter zu komplexeren Entscheidungsb2umen vor-
dringt, w2ren Verschachtelungen unvermeidlich. Prinzipiell kann
die If-Anweisung unbegrenzt verschachtelt werden, das heißt, in
jedem Block kann sich wiederum eine If-Anweisung verstecken.
Das f&hrt in aller Regel nicht zu besonders gut lesbarem Code
und sollte vermieden werden. Es gibt fast immer elegantere L/-
sungsm/glichkeiten. Oft ist es notwendig, nicht nur auf das Ein-
treten eines Ereignisses zu reagieren, sondern auch die negative
Entscheidung zu behandeln. In solchen F2llen wird die If-Anwei-
sung um Else (dt. sonst) erg2nzt. Die Anweisung oder der Block
hinter Else wird ausgef&hrt, wenn die Bedingung nicht zutrifft.
Das letzte Beispiel k/nnte man auch mit If nach dem Else schrei-
ben. Praktisch wird dabei in dem Else-Zweig noch eine weitere
ElseIf-Anweisung eingebaut. Das folgende Beispiel zeigt eine
m/gliche Anwendung:
Sandini Bib
Spracheinf(hrung 169
<%
Dim stunde As Short = 9
Select Case stunde
Case 8
Response.Write("Guten Morgen")
Case 9
Response.Write("Bisschen spXt heute?")
Case 10
Response.Write("Jetzt gibt's Zrger")
Case 11
Response.Write("Lass dich krankschreiben")
Case Else
Response.Write("Sonstwann am Tage...")
End Select
%>
Listing 3.7: Mehrfachbedingung mit Select Case aufbauen (VbKeywordSelect.aspx)
Der prinzipielle Aufbau ist aus dem Beispiel ersichtlich. In der Se-
lect Case-Anweisung selbst steht die zu testende Variable, in den
Case-Abschnitten jeweils der Testwert, der auf Gleichheit getestet
wird. Case 8 entspricht also stunde = 8.
Im Beispiel wurde bereits der Befehlsbestandteil Case Else genutzt. Case Else
Dieser Zweig der Select-Anweisung wird ausgef&hrt, wenn keine
andere Bedingung zutrifft. Die Position ist wichtig, Case Else muss
immer am Ende der Liste stehen.
Sandini Bib
170 3 Einf(hrung in Visual Basic .NET
Damit lassen sich Abfragen oft k&rzer, aber selten lesbarer gestal-
ten. Außerdem ist IIf eine Funktion und kein Sprachelement, wo-
durch der Aufruf langsamer ist als der einer echten If-Anwei-
sung.
GoTo "Sprungziel"
On Error GoTo 0
3.4.7 Schleifen
Schleifen ben/tigen Sie, um Programmteile mehrfach durchlaufen
zu lassen. Neben der Einsparung an Tipparbeit ist vor allem die
variable Festlegung der Schleifendurchl2ufe interessant. Schleifen
ohne feste Laufvariable werden durch eine Bedingung gesteuert.
Der Zustand des logischen Ausdrucks bestimmt, ob die Schleife
weiter durchlaufen wird oder nicht.
Sandini Bib
172 3 Einf(hrung in Visual Basic .NET
<%
Dim counter As Integer = 0
Dim test As Integer = 6
While test > counter
Response.Write ("Aktueller ZXhler: " & counter.ToString() &
"<br/>")
counter += 1
End While
%>
Listing 3.8: Einfache While...End While-Schleife (VbKeywordWhile.aspx)
gung so wirkt, dass der Inhalt nie durchlaufen wird. Um das je-
doch sicherzustellen, kann die Do...Loop-Schleife verwendet wer-
den. Der einzige Unterschied zu While besteht in der Art der Ab-
arbeitung und den erweiterten Bedingungsschl&sselw/rtern.
Zuerst wird die Schleife einmal durchlaufen und am Ende wird
die Abbruchbedingung getestet. Auch dann, wenn die Abbruch-
bedingung beim Schleifeneintritt False ist, wird der Block mindes-
tens einmal ausgef&hrt.
<%
Dim counter As Integer = 0
Dim test As Integer = 6
Do
Response.Write ("Aktueller ZXhler: " É
& counter.ToString() & "<br/>")
counter += 1
Loop While test > counter
%>
Listing 3.9: Einfache Anwendung der do-Schleife (VbKeywordDoLoop.aspx)
<%
Dim counter As Integer = 30
Dim test As Integer = 6
While counter > test
Response.Write("Aktueller ZXhler: " & counter.ToString() &
"<br/>")
Sandini Bib
174 3 Einf(hrung in Visual Basic .NET
counter += 1
If counter = 50 Then Exit While
End While
Response.Write("Schleifenende erreicht bei: " &
counter.ToString())
%>
Listing 3.10: Schleife mit Notausstieg mittels Exit While (VbKeywordExitWhileaspx)
Dies ist die einfachste Form der Anwendung. Das folgende Lis-
ting zeigt Schrift in verschiedenen Gr/ßen an:
<%
Dim i As Integer
For i = 10 To 24 Step 2
Response.Write ("<div style=""font-size:" É
& i.ToString() & "pt""/>")
Response.Write ("For...Next-Schleife</div>")
Next
%>
Listing 3.11: Klassische For...Next-Schleife (VbKeywordFor.aspx)
Die Schleife arbeitet mit der Laufvariablen i. Der Startwert ist 10.
Die Schleife wird solange durchlaufen, wie i kleiner oder maximal
gleich 24 ist. Nach jedem Durchlauf wird die Z2hlvariable i um
zwei erh/ht.
Die Angabe der Schrittweite mit Step kann entfallen, wenn mit der
Standarderh/hung von Eins (1) gez2hlt werden soll. Der Wert
kann im Bedarfsfall auch negativ sein, um r&ckw2rts zu z2hlen.
Ein vorzeitiges Verlassen der Schleife ist mit Exit For m/glich.
Class KlassenName
' Deklaration der Mitglieder
End Class
Allzu komplizierte Abh+ngigkeiten von Klassen oder gar der Aufbau ei-
ner Hierarchie, wie sie das Framework darstellt, ist in eigenen Projekten
extrem selten notwendig. Nur wenn Bibliotheken (Sammlungen von
t
Klassen) entwickelt werden, die fremde Entwickler nutzen sollen, ist eine
feinere Abstufung sinnvoll.
Der Sichtbereich kann nicht nur f&r eine Klasse, sondern auch f&r Mitglieder
jedes Mitglied festgelegt werden. In VB.NET werden dazu folgen-
de Schl&sselw/rter verwendet:
Schl/sselwort Bedeutung
Public Offentlich, 2berall sichtbar
Protected Friend Kombiniert Friend und Protected
Friend Sichtbar im selben Programm
Protected Offentlich, sichtbar in direkt erbenden Klassen und allen
dort vorhandenen Mitgliedern
Private Nur innerhalb der Klasse und aller ihrer Mitglieder
Die Klasse selbst kann nur mit Private, Friend oder Public dekla- Klassen
riert werden.
Sandini Bib
178 3 Einf(hrung in Visual Basic .NET
End Class
Listing 3.12: Ereignisbehandlung einer Schaltfl5che (VbEvent.aspx.vb zu VBEvent.aspx)
<body>
<form id="Form1" method="post" runat="server">
<H1>Dynamisch Ereignisse zuweisen</H1>
<P>
<asp:Button id="Button1" runat="server" É
Text="Klick mich!" />
<asp:CheckBox id="cbAuswahl" runat="server"
Text="Kein Standardereignis" /></P>
<P>
<asp:Label id="lAusgabe" runat="server">
Noch nicht geklickt
</asp:Label>
</P>
</form>
</body>
Listing 3.13: Testprogramm f(r Ereignisbehandlung (VBEventsDynamic.aspx)
Sandini Bib
Spracheinf(hrung 181
Function Grunds2tzlich wird folgende Syntax f&r eine Methode mit R&ck-
gabewert verwendet:
Exit Zus2tzlich kann den Methoden als Mitglied einer Klasse ein Zu-
griffsmodifizierer wie Public oder Private vorangestellt werden.
Die Exit-Anweisung f&hrt zum vorzeitigen Verlassen der Metho-
de und muss deshalb in einer If-Anweisung stehen.
Parameter Die Parameter sind in beiden F2llen optional, die runden Klam-
mern m&ssen jedoch immer geschrieben werden. Wenn Parameter
verwendet werden, gilt allgemein der gezeigte Aufbau Parameter-
Name As Typ. Werden Arrays &bergeben, sind hinter den Para-
meternamen runde Klammern zu setzen: ParameterArray() As Typ.
ByVal Wenn Sie Parameter in dieser Form in Visual Studio .NET eintip-
ByRef pen, werden Sie feststellen, dass vor dem Parameternamen das
Schl&sselwort ByVal hinzugef> wird. Dies sieht dann folgender-
maßen aus:
Dim a As String
Klasse.Name(a)
Ist in der Methode Name der Klasse Klasse der Parameter mit ByVal
gekennzeichnet, wird nicht das Objekt a, sondern eine Kopie &ber-
geben – quasi nur der Wert (ByVal stammt von »by value«, zu
deutsch »als Wert«). Es kann notwendig sein, dass eine Methode
Sandini Bib
Spracheinf(hrung 185
Zugriff auf das Original erhalten soll. Dann k/nnen Sie das
Schl&sselwort ByRef (»by reference«, als Verweis) verwenden.
Enderungen innerhalb der Methode wirken sich nun auf das auf-
rufende Objekt aus. Das setzt nat&rlich voraus, dass das zu 2n-
dernde Objekt 2nderbar ist – Konstanten sind hier nicht erlaubt.
End Class
Listing 3.15: @bergabe von Parametern als Referenz
(Code-Datei VbMethodReference.aspx.vb zu VbMethodReference.aspx)
Neben der Enderung von Parametern k/nnen Sie auch leere Ob- Anwendung
jekte &bergeben und durch eine Methode f&llen lassen. Funk-
tionen haben nur einen R&ckgabewert. Werden mehrere ben/tigt,
helfen Methodenaufrufe mit referenzierten Parametern weiter.
Bis auf bestimmte Situationen ist die Vorgabe ByVal grunds+tzlich rich-
tig. Die Entkopplung der Adressr+ume, wie sie standardm+ßig stattfin-
det, verringert das Fehlerrisiko und f&hrt zu lesbareren Programmen.
t
6berlegen Sie sorgf+ltig, ob ByRef wirklich notwendig ist und setzen Sie
es nur dann ein, wenn es keine andere Form der Parametermanipulation
gibt. Oft werden Eigenschaften zum Werteaustausch besser geeignet
sein. Dazu finden Sie mehr im folgenden Abschnitt.
Sandini Bib
186 3 Einf(hrung in Visual Basic .NET
Optionale Manchmal kann es notwendig sein, erst zur Laufzeit und beim
Parameter Aufruf einer Methode zu entscheiden, ob ein Parameter &berge-
ben wird oder nicht. Sie k/nnen dann das Schl&sselwort Optional
benutzen, um anzuzeigen, dass der Parameter entfallen kann. Da-
mit der fehlende Wert nicht zu St/rungen im Ablauf f&hrt, geben
Sie im Methodenkopf einen Standardwert an. Diese Angabe ist
zwingend erforderlich. Die Syntax sieht folgendermaßen aus:
var = Calc(100)
Das Beispiel mit dem Umrechnungskurs ließe sich statt mit einem
optionalen Parameter auch mit 3berladung l/sen:
var = object.Methode()
Dim p As Point
p.x = 0
p.y = 100
4 Das Beispiel ist etwas konstruiert; in einem so einfachen Konstrukt w2re ei-
ne Struktur besser geeignet als eine Klasse. Mehr Informationen dazu finden
Sie in Abschnitt 3.4.9, »Strukturen und Aufz2hlungen« ab Seite 204.
Sandini Bib
188 3 Einf(hrung in Visual Basic .NET
Das folgende Beispiel zeigt die Deklaration einer Klasse mit drei
Eigenschaften und deren Verwendung. Die Ausgabe erfolgt an
ein Label-Steuerelement, das hier nicht explizit gezeigt wird.
End Class
Public Class VbProperties
Inherits System.Web.UI.Page
End Class
Listing 3.16: Definition von Eigenschaften (VbProperties.aspx.vb)
Set(ByVal Value)
Der Typ ergibt sich aus einer expliziten Angabe oder – wie im Bei-
spiel – durch Annahme des universellen Typs Object. Vorausset-
zung daf&r ist nat&rlich, dass Option Strict als Off deklariert wur-
de. Andernfalls m&ssen alle Deklarationen den passenden
Datentyp erhalten, was im Beispiel folgendermaßen aussieht:
Sandini Bib
190 3 Einf(hrung in Visual Basic .NET
Abbildung 3.11: Intellisense erkennt, welche Zweige einer Eigenschaft zul5ssig sind.
n.NachName("Krause") = "J^rg"
n("Krause") = "J^rg"
Die Anwendung hat noch einen zweiten Effekt. Wenn das stati- Shared
sche Mitglied nicht Teil eines Objekts ist, m&sste es auch schon
vor der Instanziierung zur Verf&gung stehen. Genau das ist auch
der Fall. Das folgende Beispiel rechnet Euro in DM um (falls Sie
sich immer noch nicht daran gew/hnt haben, in Euro zu rechnen).
F&r solche Umrechnungsvorg2nge w2re eine Instanziierung sinn-
los. Mit einer statischen Methode ist die Benutzung der Klasse ein-
facher. Zuerst der HTML-Teil auf einen Blick:
Wie es Dem Aufruf der Methode Euro2DM der Klasse EuroDM geht hier
funktioniert keine Initialisierung voraus. Statische Mitglieder k/nnen sofort
benutzt werden:
EuroDM.Euro2DM(Me.TextBox1.Text)
Die 3bergabe der Werte erfolgt dann in der Phase der Instanzi-
ierung:
Dieser Abschnitt ist leicht vereinfacht, um den Rahmen des Buches nicht
zu sprengen. Konsultieren Sie spezielle Literatur zu VB.NET, um sich
mit allen M3glichkeiten vertraut zu machen. Die Darstellungen hier
sind jedoch ausreichend, um alle Beispiele dieses Buches verstehen und
verwenden zu k3nnen.
Inherits Eine Vererbung finden Sie in jeder Klasse, die der Verarbeitung ei-
ner Seite dient: Die Ableitung der Seitenklasse von der Basisklasse
Page. Das Schl&sselwort zur Steuerung der Vererbung ist Inherits.
Eine Klasse kann immer nur von genau einer Basisklasse erben.
Der Vorgang f&hrt im ersten Schritt dazu, dass die erbende Klasse
alle Mitglieder der vererbenden Klasse &bernimmt. An dieser Stel-
le kommen &brigens die Zugriffsmodifizierer ins Spiel, die bislang
nur eine untergeordnete Rolle hatten.
Zur Erinnerung: Mitglieder, die als Public gekennzeichnet wer-
den, sind &berall im Programm sichtbar. Wird dagegen Private
verwendet, sind sie außerhalb der Klasse unsichtbar. Beim Einsatz
der Vererbung ist das Verhalten gegen&ber der erbenden Klasse
zu definieren. Verwenden Sie Protected, um den Sichtbereich aus-
schließlich in erbende Klassen auszudehnen. Schreiben Sie gr/ße-
re Projekte, die sich &ber mehrere Anwendungen hinweg ausdeh-
nen, kann Friend interessant sein. Hierbei k/nnen andere Klassen
derselben Anwendung auf das Mitglied zugreifen, andere Pro-
grammteile dagegen nicht. Dieselbe Einschr2nkung mit Ausnah-
me erbender Klassen definiert die Kombination Protected Friend.
Class Punkt
Protected x As Integer
Protected y As Integer
End Class
Sandini Bib
Spracheinf(hrung 195
Class PunktVektor
Inherits Punkt
Public Vektor As Double
End Class
E MyBase dient dem Aufruf der Basisklasse, von der geerbt wur-
de.
E Me erlaubt den Zugriff auf andere Mitglieder der eigenen Klas-
se. Der Aufruf in dieser Form ist nur notwendig, wenn andern-
falls Namenskonflikte auftreten.
End Class
Listing 3.20: Vererbungskette – Erweiterung einer Basisklasse durch Vererbung
(VbClassInherits.aspx.vb)
Die erste Klasse Punkt definiert lediglich zwei Felder zur Speiche- Wie es
rung der beiden Punktwerte. Diese sind als Protected gekenn- funktioniert
Beachten Sie, dass die Syntax tats2chlich verlangt, die Inherits- Vererbung
Anweisung auf eine neue Zeile zu schreiben. Wenn Sie das st/rt,
verl2ngern Sie die Zeile mit dem Doppelpunkt:
Der Zugriff auf die von der Basisklasse ererbten Felder kann di-
rekt erfolgen. Im Fall von Namenskonflikten oder zur deutliche-
ren Lesbarkeit kann das Schl&sselwort MyBase benutzt werden:
MyBase._x = x
Eigenschaften Zwei weitere Eigenschaften erlauben den Zugriff auf die einzel-
nen Punktwerte. Beachten Sie hier, dass der Vektor nach jeder En-
derung eines Punkts neu berechnet werden muss. Genau dies leis-
ten die Eigenschaften im Set-Zweig:
Konstruktor Die dritte Klasse PunktName erweitert nun die bereits vorgestellte
Klasse PunktVektor erneut. Zus2tzlich wird dem Punkt noch ein
Name hinzugef>. Dies geschieht durch die Erweiterung des
Konstruktors und die Einf&hrung einer weiteren Eigenschaft. Der
Konstruktor nutzt den bereits vorhandenen aus PunktVektor. Um
den Aufruf durchzuleiten, erfolgt der Aufruf der Basisklasse. Dies
ist aus der Sicht von PunktName die Klasse PunktVektor, nicht
Punkt:
Sub New()
_x = 0
_y = 0
End Sub
Sandini Bib
Spracheinf(hrung 199
Nun kann sogar bei der Instanziierung entschieden werden, wel- Intellisense
che Aufrufform ben/tigt wird. Intellisense ist auch hier wieder ein
unersetzliches Hilfsmittel:
Schl/sselwort Bedeutung
Overridable Kennzeichnet eine Methode als 4berschreibbar
NotOverridable Verhindert, dass eine Methode 2berschrieben wer-
den kann. Dies ist bei Bffentlichen Methoden der
Standardfall.
MustOverride Zeigt an, dass die ableitende Klasse diese Methode
2berschreiben muss. Zugleich wird damit festgelegt,
dass die Methode nicht implementiert ist.
Tabelle 3.13: Schl(sselw8rter zur Steuerung der Vererbung auf einen Blick
Sandini Bib
200 3 Einf(hrung in Visual Basic .NET
Schl/sselwort Bedeutung
Overrides Zeigt an, dass diese Methode eine andere 2ber-
schreibt. Der Einsatz erfolgt in der erbenden Klasse.
Inherits Zeigt die Vererbung einer Klasse an
MustInherit Zeigt an, dass die Klasse vererbt werden muss, sie
wird damit zwingend zur Basisklasse
NotInheritable Verhindert, dass von der Klasse geerbt werden kann
MyBase Zugriff auf Mitglieder der Basisklasse
MyClass Zugriff auf Mitglieder der Klasse selbst. 4berschrie-
bene Mitglieder werden nicht verwendet, stattdessen
immer das Original.
Me Zugriff auf Mitglieder der Klasse selbst. 4berschrie-
bene Mitglieder werden verwendet.
Tabelle 3.13: Schl(sselw8rter zur Steuerung der Vererbung auf einen Blick (Forts.)
Interface Name
' Methoden/Eigenschaften
End Interface
Class Name
Implements Schnittstelle, Schnittstelle2
5 C# verh2lt sich hier &brigens anders. Bei der Implementierung kann dort
der Name nicht ge2ndert werden und aus rein theoretischer Sicht ist dies
auch keine gute Idee, denn es erschwert die Lesbarkeit des Codes unter Um-
st2nden enorm.
Sandini Bib
202 3 Einf(hrung in Visual Basic .NET
Implements folgt dem Kopf der Methode direkt, nicht auf der fol-
genden Zeile. Erscheint Ihnen das aus Sicht der Lesbarkeit un-
gl&cklich, denken Sie an das Zeilenumbruchzeichen »_«.
Namespace Oberster.Naechster
' Viele Klassen ...
End Namespace
Visual Studio .NET Dabei sind die Punkte zur Trennung mehr oder weniger willk&r-
lich, es kommt darauf an, wie sie die Klassen organisieren. In Vi-
sual Studio .NET gehen Sie etwas anders vor. Im Projekt wird ein
Standardnamensraum eingerichtet, dem dann alle weiteren De-
klarationen untergeordnet sind. Wenn Sie nun den Namensraum
Oberster deklarieren und dann im Code erneut das Schl&sselwort
Namespace einsetzen, entsteht sofort eine weitere Stufe der Hierar-
chie6.
Normalerweise sollten Sie also mit Visual Studio .NET nicht in die
Verlegenheit kommen, weitere Namensr2ume anzulegen. Wenn
Sie die Namensr2ume eines Projekts &berwachen m/chten, /ffnen
Sie die Klassenansicht mit (Strg-Umschalt-C). Die Namensr2ume
werden durch geschweifte Klammern angedeutet (siehe Abbil-
dung 3.16).
6 Dies ist insofern bemerkenswert, als dass sich C# auch hier wieder anders
verh2lt.
Sandini Bib
Spracheinf(hrung 203
Die Aufteilung der Programme auf Dateien hat auf die Verwen-
dung durch den Compiler und die durch Namensr2ume und
Klassen erzeugten Struktur keinen Einfluss. W2hlen Sie eine sol-
che Dateistruktur, dass Sie sich gut darin zurecht finden.
Public s As String
End Structure
End Class
Listing 3.21: Erzeugen und Nutzen einer Struktur (VbStructure.aspx.vb)
Aufzhlungen
In Programmen kommt es oft vor, dass Variablen nur eine fest Enum
umrissene Anzahl Werte aufnehmen. Denken Sie beispielsweise
an Wochentage oder Monatsnamen. In beiden F'llen w're der Da-
tentyp String zwar verwendbar, aber nicht optimal. Das Schl)ssel-
wort, mit dem Aufz'hlungen erzeugt werden, heißt Enum (vom
englischen Begriff enumeration):
Enum weekday
Montag,
Dienstag,
Sandini Bib
206 3 Einf%hrung in Visual Basic .NET
Mittwoch,
Donnerstag,
Freitag,
Samstag,
Sonntag
End Enum
Sie verf)gen damit noch nicht )ber eine Variable, sondern nur
)ber eine sehr individuelle Typdefinition. Von weekday abgeleitete
Variablen d)rfen einen der angegebenen Werte enthalten. Defi-
nieren Sie eine Variable wie )blich, um sie mit einem der Aufz'h-
lungswerte zu belegen:
Dim tag As weekday
Der Variablen tag knnen Sie nun einen der Werte zuweisen, in-
dem Sie direkt auf die Definition zugreifen:
tag = eWeekday.Montag
Der Zugriff ist wie vorher beschrieben )ber die Namen mglich. Zugriff auf
Außerdem gibt es eine spezielle Syntax f)r die Nutzung der Indi- Aufzhlungen
<%
Dim i As Integer
For i = 0 To 6
Response.Write É
(System.Enum.Format(GetType(weekday), i, "g") & "<br/>")
Next
%>
Listing 3.23: Zugriff auf eine Aufz(hlung mit variablem Index (VbEnumWeekday-
For.aspx, die Definition der Aufz(hlung entspricht der in Listing 3.22)
Formatsymbol Bedeutung
g oder G Der Name der Konstanten als Zeichenkette
x oder X Der Wert des Elements als Hexadezimalzahl
d oder D Der Wert des Elements als Dezimalzahl
Aus der Darstellung folgt auch, dass die durch das Schl)sselwort
Enum bereitgestellt Funktion keine Spracherweiterung von VB.NET
ist, sondern auf Klassen des Frameworks basiert. Starten Sie f)r
weitere Recherchen bei System.Enum.
Sandini Bib
208 3 Einf%hrung in Visual Basic .NET
3.4.10 Ausnahmebehandlung
Try...Catch... Die Anweisung, die hierzu verwendet wird, besteht aus mindes-
Finally tens zwei Schl)sselwrtern: Try und Catch. Der erste Teil wird
von Try...End Try umschlossen. Hier wird die Ausf)hrung von be-
liebigem Code versucht. Tritt ein Laufzeitfehler auf, wird – in der
.NET-Sprechweise – eine Ausnahme »geworfen«. Ist keine Be-
handlung daf)r definiert, hilft sich die CLR selbst und zeigt den
Fehler an. Sie knnen die Ausnahme aber auch »fangen« (engl. to
catch), was mit dem Schl)sselwort Catch erfolgt. Falls Sie Code
schreiben, der immer ausgef)hrt werden soll, egal ob es einen
Laufzeitfehler gab oder nicht, ist ein weiterer durch Finally einge-
leiteter Block notwendig.
Sandini Bib
Spracheinf%hrung 209
Try
Versuch 1
OK Fehler
Versuch 2
Fehler
Versuch 3
Catch e As Exception
Ende
AusnahmeBehandlung
Catch e2 As OtherException
Ende
AusnahmeBehandlung
Finally
Immer auszuführen
End Try
Das folgende Beispiel zeigt, wie die Anwendung in der Praxis er-
folgt. Abgefangen wird eine Ausnahme, die bei Berechnungen
h'ufiger auftritt: Division durch Null.
<html lang="de">
<head>
<title>Try Catch Finally</title>
</head>
<body>
<h1>Try Catch Finally</h1>
<p id="ausgabe" runat="server"/>
<p id="fehler" runat="server"/>
</body>
</html>
Listing 3.24: Abfangen einer Ausnahme (VbTryCatch.aspx)
Class Ausnahmen
Public Function rechne(ByVal x As Integer, É
ByVal y As Integer, É
ByVal opcode As Char) As String
Dim result As Integer
Try
Select Case opcode
Case "*"c
result = (x * y)
Exit Function
Case "/"c
result = (x \ y)
Exit Function
Case "-"c
result = (x - y)
Exit Function
Case Else
result = (x + y)
Exit Function
End Select
Sandini Bib
210 3 Einf%hrung in Visual Basic .NET
Catch e As Exception
Return ("<b>Fehler:</b> " + e.ToString())
End Try
Return result.ToString()
End Function
End Class
Wie es In diesem Beispiel wird eine zus'tzliche Klasse definiert, die ne-
funktioniert ben der Ausf)hrung der Aufgaben auch Fehler auswertet. Die Be-
rechnungen finden in einem Try-Block statt. L'uft dieser Block
korrekt ab, werden nachfolgende Catch-Blcke )bersprungen. Da-
mit wird die letzte Return-Anweisung erreicht:
Return result.ToString()
Tritt dagegen eine Ausnahme auf, wird der n'chste dazu passen-
de Catch-Block ausgef)hrt. Verwendet wird hier der globale Typ
einer Ausnahme, Exception. Diese Art trifft f)r alle Ausnahmen
zu. Abgeleitet werden diese Ausnahmen in dem in ASP.NET be-
ntigten Umfang von der Klasse System.SystemException. Die ei-
gentlichen Klassendefinitionen sind weit im Framework verstreut,
da fast )berall Laufzeitfehler auftreten knnen. Der h'ufig auftre-
tende Fehler »Division durch Null« wird in System.ArithmeticEx
ception definiert.
Sandini Bib
Spracheinf%hrung 211
4.1 Schnellstart
Dieser Abschnitt gibt einen kompakten >berblick )ber das Thema
und zeigt sinnvolle Verkn)pfungen mit erg'nzenden und vor-
bereitenden Kapiteln. Der Wegweiser in die Referenz hilft, die
passenden Seiten in der MSDN-Online-Referenz besonders
schnell zu finden.
E Array
Diese Klasse enth'lt Eigenschaften und Methoden zur Ver-
wendung mit Arrays. Eine Beschreibung finden Sie im Ab-
schnitt 4.2, »Verarbeitung von Arrays« ab Seite 217.
E CharEnumerator
Mit dieser Klasse wird auf einzelne Zeichen einer Zeichenkette
verwiesen.
E String
Hier sind alle Eigenschaften und Methoden zur Verarbeitung
von Zeichenketten zu finden.
E Hashtable, ArrayList, SortedList, NameValueCollection u. a.
Diese Klassen sind spezialisierte Formen von Kollektionen
und dienen der Speicherung von Werten oder Schl)ssel-/Wer-
tepaaren, kombiniert mit spezifischen Ein- und Ausgabe-
methoden. Abschnitt 4.3, »Aufz'hlungen und Kollektionen«
ab Seite 222 befasst sich mit diesen Klassen.
E Convert
Durch das typstrenge Konzept m)ssen oft Datentypen umge-
wandelt werden, wozu Convert eingesetzt wird.
E Enum
Aufz'hlungen lassen sich mit dieser Klasse erstellen und nut-
zen.
E Math
Mathematische Berechnungen basieren auf Eigenschaften und
Methoden dieser Klasse.
E Random
Diese Klasse dient der Erzeugung von Zufallszahlen.
Sandini Bib
Schnellstart 215
VB.NET erlaubt einen etwas laxeren Umgang mit Typen und De- Wie typstreng
klarationen. Sie knnen dennoch eine strenge Typbehandlung er- ist VB.NET?
Abbildung 4.4: Ableitung der Klassen zur Verarbeitung von Kollektionen und die
implementierten Schnittstellen
Die Klassen Array, ArrayList, Hashtable und Enum sind selbst Basis-
klassen einer Vielzahl anderer Klassen des Frameworks, die wie-
derum mit Aufz'hlungen arbeiten.
Die Klassen Convert, Math und Random befinden sich im Namens-
raum System.
Auch hier sei es nochmals angemerkt: Visual Studio .NET erledigt das
automatisch f!r Sie. Nur wenn Sie mit anderen Entwicklungsumgebun-
gen arbeiten, ist die explizite Deklaration in VB.NET erforderlich.
t
Sandini Bib
218 4 Die Basisklassen des Frameworks
Elemente Ein komplettes Array knnen Sie an einer bestimmten Stelle in ei-
kopieren nem anderen einf)gen, dazu wird CopyTo verwendet. Das funk-
tioniert aber nur mit eindimensionalen Arrays. Ein Teil wird da-
gegen mit Copy eingef)gt.
"Mueller", "Meier"}
Dim name As Object = "Krause"
Dim ni As Integer = Array.BinarySearch(namen,name)
ausgabe.InnerHtml += "Gefundener Index: " + ni.ToString()
End Sub
</script>
<html>
<head>
<title>Arrays</title>
</head>
<body>
<h1>Array-Methoden</h1>
<p id="ausgabe" runat="server"/>
</body>
</html>
Listing 4.1: Durchsuchen eines Arrays (ArrayMethods1.aspx)
End Function
End Class
Private Sub Page_Load()
Dim namen() As String = {"Schmidtchen", "Krause", É
"Mueller", "Meier"}
Dim daten() As String = {"1.12.1973", "13.4.1980", É
"23.8.1960", "14.9.1977"}
Array.Sort(namen, daten, New MyComparer())
Dim i As Integer
For i = 0 To namen.Length - 1 Step i + 1
ausgabe.InnerHtml += "<br/> " + namen(i) + ", " +
daten(i)
Next
End Sub
</script>
Listing 4.3: Arrays mit eigenem Sortierkriterium (ArrayMethods3.aspx)
Das Geheimnis steckt hier in der Klasse MyComparer, die die Schnitt- Wie es
stelle IComparer implementiert: funktioniert
Return 0
Damit sind alle Pfade der Methode abgedeckt, es gibt keine uner-
warteten Zust'nde mehr. Die Anwendung erfolgt durch >ber-
gabe einer Instanz der Klasse an die Sort-Methode:
Dieses Verfahren knnen Sie auch verwenden, wenn nur ein Ar-
ray oder eine der anderen Implementierungen von Sort verwen-
det wird.
Wenn Sie tiefer in die Materie einsteigen m1chten, m!ssen Sie die Tech-
nik der Schnittstellen und Implementierungen verstehen. Das gezeigte
Beispiel funktioniert, ist aber auf das absolut n1tige Minimum reduziert
worden. Die M1glichkeiten, die das .NET-Framework hier bietet, sind
enorm.
E ArrayList
Eine Werte-Liste, die 'hnlich wie ein Array verwendet werden
kann. Die Indizes sind numerisch.
E Hashtable
Die Implementierung des klassischen Hashes; die Indizes
(Schl)ssel) sind immer Zeichenketten. Wenn Objekte verwen-
det werden, wandelt Hashtable diese intern in Zeichenketten
um, wie es die Implementierung von ToString f)r diese Objek-
te verlangt.
E SortedList
Diese Klasse bietet beide Indexvarianten, Zahlen und Zeichen-
ketten, realisiert also ein Array mit dem Verhalten eines
Hashes.
E Queue
Arrays und Hashes erlauben den wahlfreien Zugriff auf die
Elemente. Bei Objekten der Klasse Queue ist dies anders. Hier
erfolgt der Zugriff nach dem FIFO-Prinzip (FIFO = First In,
First Out). Elemente, die zuerst abgelegt wurden, m)ssen auch
zuerst wieder entnommen werden.
E Stack
Wie bei der Klasse Queue ist der wahlfreie Zugriff nicht mg-
lich, das Speicherprinzip ist hier allerdings FILO (FILO = First
In, Last Out). Realisiert wird ein Stapel – das zuletzt abgelegte
Elemente muss zuerst wieder entnommen werden.
E Spezielle Kollektionen, so genannte Wrterb)cher: ListDictio
nary, HybridDictionary, StringDictionary
Diese Wrterb)cher sind spezialisierte Formen der Hashtable-
Klasse und erleichtern den Umgang mit Schl)ssel-/Wertpaaren.
Sandini Bib
224 4 Die Basisklassen des Frameworks
E NameValueCollection
Diese Kollektion wird intern eingesetzt, um Attribute und ihre
Parameter von XML- oder HTML-Tags oder auch Styleanwei-
sungen zu speichern. Verarbeiten Sie 'hnliche Daten, ist der
Einsatz auch in eigenen Programmen sinnvoll.
Allen Objekten ist gemeinsam, dass die Eintr'ge mit For Each se-
quenziell ausgelesen werden knnen.
Imports System.Collections
Die Attribute Inherits und src 'ndern sich jeweils, die korrekte
Angabe finden Sie bei den Listingunterschriften.
Sandini Bib
Aufz(hlungen und Kollektionen 225
Der Zugriff auf die Elemente erfolgt in VB.NET )ber einen Array- Eigenschaften
Schreibweise, was folgendermaßen aussieht:
element(3)
Handles MyBase.Load
ausgabe.Text = "<h3>Aus ArrayList erzeugt.</h3>"
Dim album As ArrayList = New ArrayList()
ausgabe.Text += "Erlaubt sind derzeit " É
+ album.Capacity.ToString() + " Werte"
album.Add("The Wall")
album.Add("Animals")
album.Add("Ummelgummel") ' Fehler
album.Add("Atom Heart Mother")
album.Add("Meddle")
album.Add("Wish You Were Here")
album.Add("The Final Cut")
album.Add("The Division Bell")
album.Add("The Dark Side Of The Moon")
album.Remove("Ummelgummel")
album.Insert(2, "Ummagumma")
Wie es Zuerst wird hier ein Objekt vom Typ ArrayList erzeugt:
funktioniert
Dim album As ArrayList = New ArrayList()
album.Add("The Wall")
album.Remove("Ummelgummel")
album.Insert(2, "Ummagumma")
Nullbasierter Die Indizierung ist nullbasiert. Wenn ein Element mit dem Index
Index 2 eingef)gt wird, verschieben sich die alten Elemente ab Index 2;
2 wird also 3 usw.
Sandini Bib
Aufz(hlungen und Kollektionen 227
Die Ausgabe mit For Each ist so einfach wie mglich gehalten.
Falls Ihre Liste verschiedene Objekte enth'lt, m)ssen Sie hier na-
t)rlich eine entsprechende Sonderbehandlung einf)gen.
Weitere Methoden, die Sie verwenden knnen, sind unter ande- Methoden
rem:
E Reverse
Hiermit wird die Reihenfolge der Elemente gedreht.
E Sort
Sortiert den Inhalt. Beachten Sie, dass Sie eigene Sortieralgo-
rithmen mit der Implementierung der Schnittstelle IComparer
entwickeln knnen. Wie das geht, wurde bereits im Abschnitt
»Definition eigener Suchalgorithmen« ab Seite 220 gezeigt.
E Contains
Die Methode ermittelt, ob ein bestimmtes Element in der Liste
ist.
E BinarySearch
Hiermit knnen Sie Objekte ebenfalls suchen. F)r komplizier-
tere Gebilde kann die IComparer-Schnittstelle zur Implementie-
rung eigener Suchmethoden genutzt werden.
E AddRange
F)gen Sie mit dieser Methode mehrere Elemente hinzu. Der
Parameter soll vom Typ ICollection sein; eine Schnittstelle, die
viele andere Datenlisten im .NET-Framework auch verwenden
und die sehr gut die Kompatibilit't sicherstellt, beispielsweise
zu DataView (siehe Kapitel 9, »Datenbanken und ADO.NET« ab
Seite 823).
Sandini Bib
228 4 Die Basisklassen des Frameworks
Methoden Eine Hashtable ist eine Sammlung beliebiger Objekte. Die Ablage
erfolgt mit eigenen, alphanumerischen Schl)sseln. Objekte kn-
nen anhand des Schl)ssels oder des Objekts selbst entnommen
werden. Zum Hinzuf)gen wird die Methode Add eingesetzt. Ent-
fernt werden Objekte unter Angabe des Index mit RemoveAt, bei
Angabe des Objekts mit Remove. An einer bestimmten Stelle – mit
Indexnummer – kann mit eingef)gt werden. Insert entfernt alle
Elemente.
End Class
Listing 4.6: Verwendung von Hashtable (Ausschnitt aus CollectionBooks.aspx.vb)
Das Hashtable-Objekt soll B)cher speichern. Dazu wird eine Struk- Wie es
tur definiert, die die Daten aufnimmt: funktioniert
Diese enth'lt drei Variablen, in denen der Autor, der Preis und
die Anzahl Seiten gespeichert werden.
Mit einem weiteren Objekt soll jetzt der Zugriff auf die Elemente
erfolgen. Auf direktem Wege ist das leider nicht mglich, deswe-
gen werden Schl)ssel und Werte einzeln in Instanzen von Array
List abgelegt. Lesen Sie in Abschnitt 4.3.4, »Zugriff auf Aufz'h-
lungen« ab Seite 231, wie dies mit Aufz'hlungen eleganter erfol-
gen kann. Hier zuerst die beiden ArrayList-Objekte:
Dann werden die Titel zugewiesen; dies sind die Schl)ssel der
Hashtable:
atitel.AddRange(buchliste.Keys)
Mit der Eigenschaft Values erfolgt der Zugriff auf die Strukturen:
abuch.AddRange(buchliste.Values)
Auf den Titel kann direkt )ber den Index des Arraylist-Objekts
zugegriffen werden:
DictionaryEntry. Ein Durchlaufen der Liste kann auch mit For Each
erfolgen, was folgendermaßen aussieht:
Anwendungsbeispiel
Das folgende Beispiel zeigt den Einsatz – der Zugriff erfolgt auf Tabellen
eine Kollektion von Tabellenzellen einer HTML-Tabelle: manipulieren
End Class
Listing 4.9: Dynamisches Erzeugen der Tabelle (Ausschnitt aus GetEnumarator.aspx.vb)
Bevor die Funktion im Detail behandelt wird, soll ein Blick auf die
Ausgabe das Ergebnis zeigen:
Das Programm zeigt neben der Nutzung der Aufz'hlung noch Wie es
zwei besondere Techniken, die anderswo im Buch besprochen funktioniert
werden:
Betrachten Sie zuerst den HTML-Teil. Dort wird eine Tabelle ganz Tabelle aufbauen
allgemein definiert – noch ohne irgendwelchen Inhalt:
<asp:table id="tabelle" runat="server"/>
Auch hier wird f)r jede Zelle ein entsprechendes Objekt erzeugt:
Jede Zelle wird nun mit einer Zufallszahl gef)llt. Die Datenquelle
kann nat)rlich auch anders gestaltet werden:
reihe.Cells.Add(zelle)
Ist eine Reihe fertig, wird auch diese an die Tabelle angef)gt:
tabelle.Rows.Add(reihe)
Liste aufbauen Jetzt ist noch das Formular auszuwerten. Der Vorgang besteht aus
zwei Teilen. Zuerst muss noch die Liste aufgebaut werden, aller-
dings nur beim ersten Aufruf des Programms (IsPostBack gleich
False). Dazu wird ein ArrayList-Objekt instanziiert:
Dieses wird mit so vielen Zahlen gef)llt, wie Reihen in der Tabelle
existieren:
Dieses Array wird nun als Datenquelle f)r die Liste verwendet:
liste.DataSource = arrayReihe
liste.DataBind()
Die Aufz'hlung wird nun bentigt, um eine Zeile der Tabelle aus- Zugriff auf die
zulesen. Dies passiert jedoch erst, wenn das Formular gesendet Aufzhlung
wurde, also in der Methode holeReihe, die das Ereignis onClick ser-
verseitig verarbeitet, was durch Handles sendenClick erreicht wird:
Zuerst wird der Index ermittelt, der in der Liste ausgew'hlt wur-
de:
Nun kann auf die Reihe einer Tabelle zugegriffen werden. Die
Methode GetEnumarator liefert die komplette Reihe als Objekt vom
Typ IEnumerator:
Das aktuelle Element wird nun mit der Eigenschaft Current gele-
sen:
Der Rest besch'ftigt sich mit der Ausgabe, die zu dem bereits ge-
zeigten Ergebnis f)hrt. Beachten Sie, dass in der Schleife mehrere
Zuweisungen erfolgen und deshalb der Inhalt des Steuerelemen-
tes mit dem Operator += erweitert wird.
ausgabe.Text += " " + aktuelleZelle.Text
E Current
Die einzige Eigenschaft der Schnittstelle gibt das aktuelle Ele-
ment zur)ck.
E MoveNext
Mit dieser Methode wird die Aufz'hlung durchlaufen. Jeder
Aufruf schaltet einen internen Zeiger auf diese Elemente eine
Position weiter. Sind keine Elemente mehr vorhanden, wird
False zur)ckgegeben, sonst True.
E Reset
Mit dieser Methode wird der Zeiger wieder auf das erste Ele-
ment zur)ck gesetzt.
Beide Methoden haben keinen Parameter.
4.3.5 W9rterb3cher
Wrterb)cher speichern Daten in indizierter Form. Das trifft zwar
auch f)r Hashtable zu, einige spezialisierte Klassen bieten jedoch
etwas mehr als dies.
Das folgende Beispiel liest Dateien aus einem Verzeichnis und legt
die Liste in einer Instanz des Typs SortedList ab. Gespeichert wer-
den Objekte vom Typ FileInfo. Die »sortierende« Klasse enth'lt
nur diesen Typ und wird außerdem um zwei Methoden erweitert:
Sandini Bib
238 4 Die Basisklassen des Frameworks
Wie es Die Standardmethode ToString, die alle Klassen kennen, wird hier
funktioniert )berschrieben. Wenn Sie einer SortedList-Instanz ein Objekt als
Schl)ssel hinzuf)gen, wird intern ToString aufgerufen, um eine
Zeichenkette als Schl)ssel verwenden zu knnen. Standardm'ßig
gibt ToString den Namen der Klasse zur)ck, wenn es sich um eine
eigene Definition handelt (hier: »MyFile«). Schl)ssel m)ssen je-
doch eindeutig sein, deshalb wird die Methode )berschrieben.
Als R)ckgabewert dient der Dateiname:
Return _file.Name
Die Liste muss nun noch benutzt werden. Dies geschieht hier in
der Page_Load-Methode:
Datenbindung Die Datenbindung f)hrt dann zur >bertragung der Daten zur
Laufzeit:
SortedList.DataBind()
Die Zeile zur Ausgabe der Dateigrße sieht komplizierter aus, ent-
h'lt aber letztlich keine Besonderheiten:
1 C# verh'lt sich hier )brigens anders, ein Austausch der Code-Datei reicht
zum Sprachwechsel in solchen F'llen nicht aus.
Sandini Bib
Aufz(hlungen und Kollektionen 241
Lesen Sie diesen Ausdruck von links nach rechts. Die ersten beiden Datenbindungs-
Elemente umfasst den Zugriff auf das aktuelle Element des Contai- ausdr0cke
entwickeln
ners: Container.DataItem. Von diesem wird wieder der Schl)ssel ent-
nommen: .Key. Nun steht das Objekt – wiederrum implizit konver-
tiert – vom Typ MyFile zur Verf)gung. Dann folgt ein direkter
Zugriff auf das Feld _file, das ein FileInfo-Objekt enth'lt. Dessen Ei-
genschaft Length wird nun gelesen und in eine Zeichenkette umge-
wandelt, wozu wieder ToString zum Einsatz kommt.
Dieser Abschnitt zeigte mehrere Methoden zum Umgang mit Lis- Vorteile von Listen
ten. Dies beinhaltet zum Einen die Mglichkeit, Objekten Sortier-
kriterien mitzugeben und sie damit automatisch sortieren zu las-
sen, was allein durch die Verwendung von SortedList passiert. Es
ist wichtig den Vorteil darin zu erkennen, dass Sie im Code keine
Methode Sort() einsetzen m)ssen. Ihr Programm wird universel-
ler, denn es sortiert immer so, wie die gespeicherten Objekte es er-
fordern. Der zweite Vorteil besteht in der Liste selbst, die die
Schnittstelle IEnumerable implementiert. Allein dadurch kann die
Zuweisung an Daten-Steuerelemente erfolgen. Das Erzeugen, F)l-
len und Ausgeben besteht also letztlich aus nur vier Zeilen Code.
Das ist, auch wenn es auf den ersten Blick kompliziert anmutet,
an Einfachheit nicht zu schlagen.
Abbildung 4.11: Das aktuelle Verzeichnis, unsortiert und sortiert als Liste (unten)
Sandini Bib
242 4 Die Basisklassen des Frameworks
System.Collections.Specialized
Imports System.Collections.Specialized
hl(fi.Name) = fi.Length.ToString()
Sandini Bib
244 4 Die Basisklassen des Frameworks
FileList.DataSource = hl.Keys
<body MS_POSITIONING="GridLayout">
<h1>HybridDictionary</h1>
WWhlen Sie Verzeichnis, dessen Inhalt angezeigt werden soll:
<form id="HybridDictionary" method="post" runat="server">
<asp:DropDownList Runat="server" ID="Directories"/>
<input type="submit" value="Anzeigen"/>
</form>
<asp:Repeater Runat="server" ID="FileList">
<HeaderTemplate><ul></HeaderTemplate>
<ItemTemplate>
<li><%# Container.DataItem %></li>
</ItemTemplate>
<FooterTemplate></ul></FooterTemplate>
</asp:Repeater>
</body>
Listing 4.13: Auswahlliste und Ausgabeliste (Ausschnitt aus HybridDictionary.aspx)
Der Zugriff auf die Datenelemente der Liste ist hier extrem ein-
fach, da die Auswahl eindeutiger Daten bereits zuvor erfolgte:
Abbildung 4.12: Auswahl des Verzeichnisses und Ausgabe der enthaltenen Dateien
<body MS_POSITIONING="GridLayout">
<h1>StringDictionary</h1>
<img src="data/bild" alt="Alternativer Text" É
border="1" height="100" width="200" class="Bild" É
id="MyPicture" runat="server"/>
<p/>
<asp:Repeater Runat="server" ID="Attributes">
<HeaderTemplate><ul></HeaderTemplate>
<ItemTemplate>
<li>
<%# Container.DataItem.Key %>
=
<%# Container.DataItem.Value %>
</li>
</ItemTemplate>
<FooterTemplate></ul></FooterTemplate>
</asp:Repeater>
</body>
Listing 4.14: Auslesen und Ausgaben von Attributen eines HTML-Elements
(StringDictionary.aspx)
Wie es Der Aufbau der Liste erfolgt in einer Zeile, wobei die Kollektion
funktioniert der Schl)ssel durchlaufen wird:
sd.Add(key, MyPicture.Attributes(key))
Dasselbe gilt auch f)r die GET-Parameter eines URL. Wenn Sie
diese Werte nun zum Zweck der Weiterverarbeitung in einem
Wrterbuch speichern mchten, verwenden Sie NameValueCollec
tion. Dieser Typ hat ein definiertes Verhalten f)r den Fall, dass
Sie einen Schl)ssel abrufen, der mehrfach auftritt. Sie erhalten in
diesem Fall eine kommaseparierte Liste der Werte.
Abbildung 4.15: Ausgabe der Werte nach der Speicherung im W:rterbuch unter einem
Schl%ssel
Da eine solche Liste nicht immer bentigt wird, bietet die Klasse
einige spezielle Eigenschaften und Methoden, die )ber die Mg-
lichkeiten der anderen Wrterb)cher hinausgehen. Normalerwei-
se steht immer eine Eigenschaft Keys zur Verf)gung, die eine Auf-
z'hlung – meist von ICollection stammend – der Schl)ssel
zur)ckgibt. Damit kann beispielsweise For Each etwas anfangen.
Dies wurde im Beispiel in Listing 5.14 gezeigt. Wenn Sie aber alle
Werte eines Schl)ssels einzeln bentigen, verwenden Sie GetValu
es("SchlSsselname").
Infos 0ber Die oben bereits angesprochenen Einsatzf'lle sind POST- und
Request.Form GET-Parameter. Bevor Sie nun auf die Idee kommen, die Kollek-
und Request.
QueryString
tionen der Parameter in Instanzen der Klasse NameValueCollection
finden Sie in zu speichern, lohnt ein Blick auf die Liste der Eigenschaften und
Kapitel 8 Methoden von Request.Form und Request.QueryString. Beide Eigen-
schaften geben Objekte zur)ck, die selbst von NameValueCollection
abstammen. Insofern er)brigt sich der Einsatz f)r diese F'lle ei-
gentlich, das Framework hat Ihnen hier einiges an Arbeit abge-
nommen. Allerdings knnen Sie eine direkte Zuweisung vorneh-
men, wie sie im folgenden Beispiel verwendet wird:
End If
End Sub
End Class
Listing 4.16: @bernahme von Formularwerten
(Ausschnitt aus NameValueCollection.aspx.vb)
Die Zuweisung der Form-Kollektion ist der Schl)ssel dieses Bei- Wie es
spiels: funktioniert
nvc = Request.Form
Abbildung 4.16: Getrennte Anzeige der Werte, die in der Liste gew(hlt wurden
Sandini Bib
250 4 Die Basisklassen des Frameworks
Felder
Zwei statische Felder dienen als Quelle zweier Konstanten: E f)r
Eulersche Zahl und PI f)r Pi.
Methoden
Alle Methoden der Klasse Math sind statisch. Sie knnen also nicht Abs
–3.Abs schreiben, um den absoluten Betrag zu bestimmen, sondern
m)ssen folgende Notation w'hlen: Math.Abs(-3). Die Anwendung
entspricht dem in anderen Programmierumgebungen )blichen
Aufruf von eingebauten Funktionen, von der vorangestellten
Klasse Math abgesehen.
Mathematisch korrekt runden Sie dagegen mit Round, ein zweiter Round
Parameter gibt die Anzahl der Kommastellen an. Potenzen wer- Pow
Sign
den mit Pow berechnet. Das Vorzeichen wird mit Sign ermittelt,
wobei die Zahlen –1, 0 oder 1 zur)ckgegeben werden, nicht True
oder False.
grenzt viele.
Sandini Bib
252 4 Die Basisklassen des Frameworks
4.5 Zufallszahlen
Zufallszahlen sind immer wieder ein Thema in der Programmie-
rung. Im Namensraum System gibt es die Klasse Random, die das Er-
zeugen derartiger Nummern sehr komfortabel gestaltet.
rnd ist nun das Objekt, das Zufallszahlen aller Art liefern kann.
Verwenden Sie folgende Methoden:
E Next
Hiermit wird eine Zufallszahl erzeugt. Ohne Parameter im ge-
samten Wertebereich Int32, mit einem Parameter zwischen 0
und dem angegebenen Wert, mit zwei Parametern zwischen
diesen beiden.
E NextDouble
Diese Methode erzeugt eine Gleitkommazahl vom Typ Double
grßer 0.0 und kleiner als 1.0.
E NextBytes
Die Methode f)llt ein beliebig großes Arrays aus Bytes mit
Bytewerten (0 bis 255).
Das zuvor erzeugte Random-Objekt rnd f)llt dies nun mit einer zu-
f'lligen Folge:
rnd.NextBytes(b)
Der Rest des Programm besorgt die Ausgabe, die zeigt, wie die
Methoden reagieren:
Wie )blich bei Zufallszahlen basiert der Algorithmus auf einem Startwerte
Startwert. Die Zuweisung erfolgt mit der Instanziierung. Der
Konstruktor verwendet einen Zeitstempel, wenn kein Startwert
angegeben wurde. Alternativ kann auch ein Startwert vorgegeben
werden:
Dim rnd As Random = New Random(12345)
4.6 Zeichenketten
Der Verarbeitung von Zeichenketten kommt generell eine große
Bedeutung zu, denn die Datenstrme zwischen Webserver und
Browser sind letztlich Folgen von Zeichen.
Imports System
Auch hier sei es nochmals angemerkt: Visual Studio .NET erledigt das
t automatisch f!r Sie. Nur wenn Sie mit anderen Entwicklungsumgebun-
gen arbeiten, ist die explizite Deklaration in VB.NET erforderlich.
Eigenschaften
Die Zeichen einer Die Klasse String verf)gt )ber zwei Eigenschaften, Chars und
Zeichenkette Length. Mit Chars erhalten Sie Zugriff auf einzelne Zeichen der Zei-
chenkette. Beachten Sie bei der Angabe des Indizes, dass dieser
bei 0 beginnt. Length ermittelt die L'nge der Zeichenkette.
zk.Chars(6)
Die L'nge wird durch Anwendung der Eigenschaft Length ermit- Length
telt und f)r die Ausgabe mit ToString in eine Zeichenkette konver-
tiert:
zk.Length.ToString()
Der Unterschied f'llt auf, wenn Sie aus einer Zeichenkette, die aus
Ziffern besteht, ein Zeichen entnehmen und als Ziffer verwenden
mchten. Nahe liegend w're folgende Schreibweise:
Freilich stellt sich hier die Frage, ob man so umst'ndlich auf Zei-
chen einer Zeichenkette zugreifen muss. Ein Blick auf die Zeichen-
ketten-Methoden lohnt deshalb.
ToCharArray Auf alle Zeichen kann auch mit ToCharArray zugegriffen werden –
diese Methode erzeugt aus den Zeichen ein Array mit Elementen
vom Typ Char. Die Definition erfolgt folgendermaßen:
Die Methode verlangt die Angabe des ersten und letzten Zei-
chens, das kopiert werden soll. Im Beispiel wird die gesamte Zei-
chenkette verwendet, das erste Zeichen hat den Index 0, das letzte
wird mit Length bestimmt:
azk = zk.ToCharArray(0, zk.Length)
Die Umkehrfunktion dazu ist Join. Als neues Trennzeichen kann Join
nur eine Zeichenkette angegeben werden. Zwei optionale Parame-
ter bestimmen den ersten Index und die Anzahl der Elemente des
verwendeten Arrays.
Beachten Sie hier, dass Join eine statische Methode ist, die nicht
auf eine Zeichenketteninstanz angewendet werden kann. Schrei-
ben Sie stattdessen den Klassennamen davor: String.Join.
Formatsymbol Bedeutung
C Whrung
D Dezimalzahl
E Exponentialzahl
F Gleitkommazahl (Float)
N Numerisch
P Prozentwert
R Erzeugter Wert wird so dargestellt, dass eine R3ck-
konvertierung m9glich ist
X Hexadezimalzahl
In diesem Abschnitt wird nur auf die Formatierung von Zahlen und Zei-
chenketten eingegangen. Wenn als Parameter andere Datentypen einge-
setzt werden, haben die Formatierungszeichen eine grundlegend andere
Bedeutung. In den entsprechenden Abschnitten wird darauf explizit hin-
gewiesen.
E StartsWith, EndsWith
Diese Methoden geben true zur)ck, wenn eine Zeichenkette
mit bestimmten Zeichen beginnt bzw. endet.
E PadLeft, PadRight
Mit diesen Methoden kann eine Zeichenkette bis zu einer be-
stimmten Anzahl Zeichen aufgef)llt werden.
Sandini Bib
Zeichenketten 261
E IndexOfAny, LastIndexOfAny
Analog zu den Index-Methoden wird das Auftreten bestimm-
ter Zeichen festgestellt, als Eingabewert kann ein Array aus
Zeichen genutzt werden.
E CopyTo
Diese Methode kopiert eine Anzahl Zeichen an eine bestimmte
Position eines Arrays aus Zeichen.
E Concat
Dies ist eine statische Methode, die der Verkn)pfung von Zei-
chenketten in Situationen dient, in denen der Verkn)pfungs-
operator + nicht angebracht ist.
E System.Web.HttpWriter
Diese Klasse dient der Ausgabe von Zeichen )ber HttpRespon-
se. Alle Ausgaben zum Browser nehmen diesen Weg, meist je-
doch intern, sodass der direkte Aufruf selten in Frage kommt.
E System.Web.UI.HtmlTextWriter
Diese Klasse dient der formatierten Ausgabe von HTML in ei-
ner WebForm. Steuerelemente knnen diese verwenden, um
HTML zu schreiben.
E System.IO.StreamWriter
Mit dieser Klasse werden allgemeine Datenstrme kontrolliert,
beispielsweise solche zu einer Datei, einem Ger't usw. Der
Ausgabedatenstrom erfolgt hier byteweise.
handeln. Fr)her gab es bei der Behandlung von Daten keinen Un-
terschied zwischen Text und Bytes. Bytes stellten die Zeichen mit
den Codes 0 bis 255 dar (1 Byte enth'lt 8 Bits, 8 gesetzte Bin'rstel-
len entsprechen dezimal 255). Text bestand meist aus ASCII, einer
Codiertabelle, die den Zahlenwerten Zeichen zuordnet.
Im Zuge der Internationalisierung entstand Bedarf an mehr Zei-
chen, als die Darstellung mit 1 Byte ermglichte. Eine anerkannte
Norm f)r breitere Zeichendarstellungen ist Unicode. Wenn aber ein
Textzeichen mehr als 1 Byte umfasst, taugt das byteweise Schreiben
von Daten nicht mehr, denn es w)rde sehr schnell passieren, dass
der Text »mitten im Zeichen« abbricht. Deshalb sind spezialisierte
Klassen f)r die Zeichenkettenverarbeitung notwendig. In .NET er-
folgt die Zeichenkettenverarbeitung mit der Klasse StringWriter.
Imports System.IO
Wenn von einer zeichenspezifischen Codierung die Rede ist, sind Codierung
auch verschiedene Codierverfahren zu betrachten. Auch wenn
Unicode eine zentrale Rolle auf Windows-Systemen spielt, sind
aufgrund der notwendigen Interoperabilit't Umwandlungen in
andere Systeme notwendig. Die Klasse StringWriter stellt die Ei-
genschaft Encoding bereit, die Angaben zur aktuellen Codierung
enth'lt.
Encoding Mit Encoding wird die Codierung eines Textes festgelegt oder ge-
'ndert. Verf)gbar sind folgende Einstellungen f)r StringWriter:
E Encoding.ASCII
E Encoding.Unicode
E Encoding.UTF7
E Encoding.UTF8
sb.Append("Zeichenkette")
sb.Append(23)
Methoden Der Aufruf von ToString ist nicht notwendig. Wenn formatierte
Werte )bergeben werden sollen, wird AppendFormat eingesetzt.
Sandini Bib
Regul(re Ausdr%cke 267
Mit der Eigenschaft Capacity ermitteln Sie die aktuelle Kapazit't Eigenschaften
bzw. legen diese fest. Die tats'chliche Anzahl Zeichen wird dage-
gen mit Length ermittelt.
Was sind regulre Regul're Ausdr)cke (aus dem Englischen: regular expressions)
Ausdr0cke? beschreiben Suchmuster. Man kann damit nach Zeichen in einer
Zeichenkette oder einem Text suchen – nicht mehr, aber auch
nicht weniger. Das geht freilich mit einfachen Suchfunktionen
auch. Oft fehlt es aber an einer klaren Definition, was eigentlich
gesucht werden soll. Wenn Sie in einem l'ngeren Text nach Stel-
len suchen, die W'hrungsangaben beinhalten, dann hilft eine
normale Suchfunktion nicht. Viele Suchfunktionen in Editoren,
Textverarbeitungen und anderen Programmen, die Textstellen su-
chen (wie beispielsweise Visual Studio .NET), nutzen deshalb
auch regul're Ausdr)cke. Diese erlauben auch die Suche nach all-
gemeineren Angaben. Die Mglichkeiten sind dabei aber so um-
fangreich, dass es sich schon wieder lohnt, ganze B)cher dar)ber
zu schreiben. Die Vielfalt der Funktionen und die M'chtigkeit der
Definitionen f)hrt dann auch zu diesen unlesbaren, verwirrenden
Konstrukten.
Sandini Bib
Regul(re Ausdr%cke 269
steht, dann ist der Entwurf und die Nutzung nicht schwieriger als
mit jedem anderen St)ck Code auch. Sie m)ssen sich die Zeit neh-
men, einen regul'ren Ausdruck sorgf'ltig zu entwerfen und zu
testen. Niemand – auch Profis nicht – schreiben einen neuen Aus-
druck, der vielleicht nur 10 oder 20 Zeichen umfasst, in ein paar
Sekunden auf. Intern arbeitet auch nicht ein einfacher Musterver-
gleich, sondern die Regex-Maschine; ein Programm, das die Aus-
dr)cke auflst und ausf)hrt.
Das folgende Muster sucht nach dem HTML-Tag <h1>, <h2> usw: HTML-Tags suchen
<h\d>
Das ist nun wenig spektakul'r, weil diese Aufgabe auch eine nor-
male Suchfunktion erf)llen w)rde. So ein Suchmuster wird nun
von links nach rechts abgearbeitet und »gleitet« dabei )ber den
Text, der durchsucht werden soll. Wird eine >bereinstimmung
gefunden, entsteht ein so genannter »Match« – ein Treffer. Im Bei-
spiel stehen alle Zeichen f)r sich selbst, außer \d – dies ist ein
Steuerzeichen, dass f)r ein Zahlzeichen steht. Dieser Ausdruck er-
kennt allerdings auch <h9>, was in HTML nicht vorkommt. Regu-
l're Ausdr)cke arbeiten Zeichenweise. Jedes Zeichen kann aber
unterschiedlich komplex definiert werden. Was hier bentigt
wird, ist eine Zeichenklasse, die nur die Ziffern 1 bis 6 umfasst.
Zeichenklassen werden in eckige Klammern gesetzt:
<h[123456]>
Die gesamte Klasse steht dennoch nur f)r ein Zeichen. Eleganter
ist der folgende Ansatz:
<h[1-6]>
Sandini Bib
270 4 Die Basisklassen des Frameworks
E ^[_a-z0-9-]+
Dieser Teil untersucht den E-Mail-Namen auf g)ltige Zeichen.
Erlaubt sind neben Ziffern und Buchstaben noch Minuszei-
chen und Unterstriche. Außerdem soll der Ausdruck von Be-
ginn an untersucht werden, was mit dem Symbol ^ erreicht
wird.
E ^[_a-z0-9-]+(\.[_a-z0-9-]+)*
Dieser Ausdruck akzeptiert auch den Punkt, allerdings nicht
am Anfang oder Ende des Namens. Die Gruppierung erlaubt
die Wiederholung des zweiten Teils, er kann aber auch entfal-
len. Damit sind Konstruktionen wie »joerg.krause« oder
»joerg« oder »joerg_krause.vbnet« erlaubt.
^[_a-zA-Z0-9-]+(\.[_a-zA-Z0-9-]+)*@ É
([a-zA-Z0-9-]+\.)[a-zA-Z]{2,4}$
Der Ausdruck ist keineswegs perfekt. Es gibt immer noch F'lle, die
unzul'ssig sind und nicht erkannt werden. Aber er ist schnell und
f'ngt die meisten Tippfehler oder bewusst unsinnige Angaben ab.
<body>
<h1>RegulWre AusdrScke</h1>
<form runat="server" ID="Form1">
<asp:textbox runat="server" id="email"/>
<asp:button runat="server" id="send" text="PrSfen"
onclick="CheckEmail_OnClick"/>
</form>
<p id="ausgabe" runat="server"/>
</body>
Listing 4.24: Praktische Nutzung regul(rer Ausdr%cke (RegexCheckEmail.aspx)
Sandini Bib
272 4 Die Basisklassen des Frameworks
Die Pr)fung des Inhalts des Feldes email erfolgt mit einer in der
Code-Datei hinterlegten Ereignisbehandlungsmethode, die fol-
gendermaßen definiert wird:
Der Ausdruck in der Variablen rxmail ist hier gegen)ber der vor-
gestellten Version noch um diverse Klammern erweitert worden.
Runde Klammern dienen der Gruppierung, gehen also in die
Analyse des Suchmusters selbst nicht ein, sondern steuern die
R)ckgabe von Teilen des Ausdrucks.
Die Analyse basiert auf einer Instanz der Regex-Klasse, die folgen- Wie es
dermaßen erzeugt wird: funktioniert
ma = rx.Match(email.Text)
In ma ist nun das Match-Objekt enthalten, der Ausdruck selbst wur- Match
de bereits abgearbeitet. Match ist sowohl eine Klasse, als auch eine
Kollektion. Wenn das Suchmuster im durchsuchten Text mehr-
mals gefunden wird, enth'lt Match mehr als ein Element. Wenn
die Suche allgemein erfolgreich war – also ein oder mehr Treffer
vorhanden waren, ist die Eigenschaft Success gleich True. In die-
sem Fall wird der Ausdruck weiter untersucht:
If ma.Success Then
Jedes Element der Kollektion Match enth'lt eine Eigenschaft Groups. Groups
Diese Eigenschaft gibt ein Objekt der Klasse Group zur)ck. Diese
Sandini Bib
274 4 Die Basisklassen des Frameworks
Klasse erlaubt den Zugriff auf die durch runde Klammern gebil-
deten Gruppen. Eine wichtige Eigenschaft ist Count – die Anzahl
der Gruppen.
Die Gruppen selbst bilden eine Kollektion. Der Zugriff erfolgt des-
halb wieder in der )blichen Arrayschreibweise:
Bedingung Beschreibung
^ Beginn des Musters
$ Ende des Musters
\A Unbedingter Beginn auch bei mehrzeiligen Texten
Bedingung Beschreibung
\Z Unbedingtes Ende auch bei mehrzeiligen Texten oder vor
dem Zeilenumbruchzeichen \n
\z Unbedingtes Ende auch bei mehrzeiligen Texten
Zeichen Bedeutung
\uNNNN Unicode-Zeichen mit dem Code NNNN (Hexadezimale
Angabe). ASCII-Zeichen nutzen das hintere Byte, ein Leer-
zeichen wird also als \u0020 geschrieben.
\n Zeilenumbruch
\r Wagenr3cklauf
\0XXX Oktale Angabe eines Zeichencodes mit ein bis drei Zahlen
von 0 bis 7.
\xHH Hexadezimale Angabe eines Zeichens
\\ Der Backslash selbst
Der Bildung von Zeichenklassen liegen fast alle regul'ren Aus- Bildung von
dr)cke zugrunde. Die Idee dahinter ist eine Beschreibung eines Zeichenklassen
bestimmten Zeichens im Suchmuster. Wenn an einer Stelle eine
Zahl zwischen 0 und 4 auftreten darf, schreibt man eine Zeichen-
klasse: [0–4] oder [01234]. In jedem Fall repr'sentiert diese Klasse
nur ein Zeichen.
Zeichen Bedeutung
. Der Punkt reprsentiert jedes beliebige Zeichen
[abcd] Eine Klasse wird durch eckige Klammern gebildet. Darin
stehen die Zeichen, die die Klasse bilden oder die Sonder-
zeichen aus der Tabelle 4.3.
[^abcd] Eine Klasse, in der die aufgef3hrten Zeichen nicht enthalten
sind.
[a-z] Mit Minuszeichen werden Bereiche von Zeichen definiert.
\p{name} Vordefinierte Zeichenklasse name.
\P{name} Alles außer dem Inhalt der vordefinierten Zeichenklasse
name.
\w, \W Wortzeichen bzw. kein Wortzeichen
Zeichen Bedeutung
2
\s, \S Whitespace bzw. kein Whitespace
\d, \D Zahlzeichen bzw. keine Zahlzeichen
\b, \B Wortgrenze bzw. keine Wortgrenze
Wiederholungs- Wenn Sie mehr als nur ein Zeichen bentigen, m)ssen Sie einen
operatoren der Wiederholungsoperatoren angeben.
Zeichen Bedeutung
* Kein oder beliebig viele Zeichen
+ Ein oder beliebig viele Zeichen
? Kein oder genau ein Zeichen
{n} Genau n Zeichen
{n,} Mindestens n Zeichen
{n.m} Mindestens m jedoch h9chstens n Zeichen
*? Das nachgestellte Fragezeichen macht den Ausdruck in die-
sem Bereich »ungierig«. Normalerweise sind regulre Aus-
+?
dr3cke »gierig«, f3hren also die Pr3fung solange fort, wie es
?? geht, auch wenn die Erf3llung bereits m9glich war. Dieses
Verhalten kann mit dieser Notation unterdr3ckt werden.
Konstrukt Beschreibung
(?o) F3r o k9nnen Sie eine oder mehrere der folgenden
(?-o) Optionen einsetzen:
E i
ignoriert Groß- und Kleinschreibung
E m
Mehrzeiliger Modus, ^ und $ sind am Anfang und Ende jeder
Zeile g3ltig
Konstrukt Beschreibung
E s
Einzeilenmodus, . erkennt auch das Zeilenendezeichen
E x
Ignoriere Whitespaces, jedoch nicht in Zeichenklassen
Der ersten Teil beginnt mit einer Wortgrenze \b. Danach wird als Gruppen
Wort erkannt, was nur aus Buchstaben besteht: ([a-z]+). Selbst- verwenden
Alternativen verwenden
Wenn ein Muster aus mehr als einem Basiswert besteht, sind Al-
ternativen gefragt. Es gibt mehrere Mglichkeiten, alternative Be-
dingungen zu formulieren:
Sandini Bib
278 4 Die Basisklassen des Frameworks
Konstrukt Beschreibung
| Trennt zwei oder mehr Muster: aa|ab|bb
(?(ausdruck)y|n) F3hrt den Zweig y aus, wenn der ausdruck 3ber-
einstimmt, sonst n.
(?(name)y|n) F3hrt den Zweig y aus, wenn die benannte Gruppe
name 3bereinstimmt, sonst n.
Der Umgang mit den letzten beiden Optionen ist keineswegs trivi-
al, aber ausgesprochen flexibel. Man kann damit gut einige Zeilen
konventionellen Codes sparen. Im Ja- bzw. Nein-Zweig steht ein
weiteres Suchmuster, um weitere Teile des Ausdrucks zu pr)fen.
1. ([Zeichenklasse])+
2. ([Zeichenklasse]+)
Im ersten Fall bildet das Zeichen eine Gruppe, die sich wieder-
holen darf. Im zweiten Fall werden die Zeichen wiederholt, und
dann wird eine Gruppe gebildet. Beide erkennen dasselbe Such-
muster. Unterschieden wird durch die Schreibweise die Art der
Repr'sentation der Fundstellen im Ergebnis.
Im ersten Fall werden die Ergebnisse als Elemente der Groups-Kol-
lektion abgelegt. Es handelt sich tats'chlich um typische Gruppen.
Sandini Bib
Regul(re Ausdr%cke 279
Im zweiten Falle wird jedoch der Inhalt der Gruppe aus Fundstel-
len gebildet. Wenn Sie auf die Fundstellen zugreifen mchten,
hilft die Capture-Kollektion.
Wie an der ersten Zeile »Treffer« zu erkennen ist, wird der Aus-
druck in beiden F'llen erkannt und auch als gleichartig bewertet.
Diese Zeile entsteht durch Zugriff auf das erste Element der
Groups-Kollektion:
ma.Groups(i)
mc = ma.Groups(i).Captures
ausgabe.InnerHtml += mc.Count.ToString()
ausgabe.InnerHtml += "<br/> Ausgabe der É
Captures-Kollektion: "
If (mc.Count > 0) Then
Dim j As Integer
For j = 0 To mc.Count - 1 Step 1
ausgabe.InnerHtml += "[" + mc(j).Value + "]"
Next
End If
Next
Else
ausgabe.InnerHtml = "<b>Der Ausdruck ist ungSltig</b>"
End If
End Sub
End Class
Listing 4.26: Das vollst(ndige Programm zum Zugriff auf Capture-Gruppen
(RegexCapture.aspx.vb)
Gruppierung Beschreibung
() Einfache Gruppe
(?<name> ) Gruppe, deren Inhalt einem Element der
(?'name' ) Captures-Kollektion mit dem Index name zugewiesen
wird
(?: ) Gruppe, die nicht in die Groups- oder
Captures-Kollektion aufgenommen werden soll
(?= ) Vorausschauende zutreffende Bedingung
(?! ) Vorausschauende unzutreffende Bedingung
(?<= ) Zur3ckschauende zutreffende Bedingung
(?<! ) Zur3ckschauende unzutreffende Bedingung
(?> ) Unterdr3ckt die Gierigkeit eines Teilausdrucks
Bedingte Gruppen Etwas schwieriger erscheint der Umgang mit Bedingungen. Hier-
bei wird ein Teil des Ausdrucks – vor oder nach dem betroffenen
Teilausdruck – in die Pr)fung mit einbezogen, nicht jedoch in die
Selektion. Damit lassen sich Konstruktionen der Art »Pr)fe, ob an
der Stelle eine Zahl ist, aber nur dann, wenn dieser Zahl ein Buch-
stabe folgt«. Der Ausdruck w're jedoch g)ltig, wenn der Zahl ein
Sonderzeichen folgt.
Wenn Sie nun eine Zeichenfolge der Art »12cc« pr)fen, ist dieser
Ausdruck nicht g)ltig, »12_« dagegen wird akzeptiert, ebenso wie
»1234«. In allen F'llen wird aber lediglich »12« als Ergebnis des
ersten Elements der Match-Kollektion zur)ckgegeben, denn der be-
dingte Teil interessiert hier nicht.
Hier werden nun ebenfalls zwei Ziffern erkannt, die jedoch von
einem vorausgehenden Buchstaben begleitet werden m)ssen. Das
Suchwort »23c21x88« w)rde als Resultat »12« zur)ckgeben, weil
die Ziffernfolge »12« als erste von einem Buchstaben angef)hrt
wird.
E Basisdatentypen
IsArray, IsClass, IsEnum
E Parametertypen
IsByRef
E Zugriffsebene
IsPrivate, IsPublic, IsSealed usw.
E Werttypen
IsValueType
End Sub
</script>
<html>
<head>
<title>Datentypen</title>
</head>
<body>
<h1>Datentypen</h1>
<p id="ausgabe" runat="server"/>
</body>
</html>
Listing 4.27: Ermittlung von Datentypen (TypeGet.aspx, ohne Code-Behind-Datei)
Die aktuelle Zeit bezieht sich immer auf den Server. Denken Sie daran,
wenn Sie die Angabe zur Begr!ßung verwenden, dass Benutzer in ande-
ren Zeitzonen leben k1nnen.
t
Das folgende Programm verwendet drei Zeitdarstellungen:
Sollen Datum und Zeit getrennt werden, verwenden Sie die Eigen-
schaften Date bzw. TimeOfDay. Dazu muss jedoch eine Instanz gebil-
det werden. Die folgenden Beispiele nutzen denselben HTML-Teil
wie das erste, er wird deshalb nicht erneut wiederholt.
Ticks Die Zeit enth'lt den Anteil in der Genauigkeit, die die Ticks bieten
(100 Nanosekunden). Das wird nicht oft bentigt, deshalb ist eine
Abtrennung mit Zeichenketten-Methoden denkbar:
Sandini Bib
Datum und Zeit 287
Schaltjahr Um zu ermitteln, ob ein Jahr ein Schaltjahr ist, verwenden Sie die
statische Methode IsLeapYear, die als Argument die Jahreszahl er-
wartet.
Zeitwerte Analog dazu werden f)r die Zeiten die Eigenschaften Hour, Minute,
Second und Millisecond verwendet. Die Ticks werden mit der
gleichnamigen Eigenschaft Ticks ermittelt. Der Datentyp, der zu-
r)ckgegeben wird, ist Long.
4.9.2 Datumsberechnungen
Berechnungen mit Datumswerten sind im .NET-Framework sehr
einfach. Dazu m)ssen Sie nat)rlich auch )ber Objekte verf)gen,
die nicht das aktuelle, sondern ein ganz spezifisches Datum ent-
halten. Dies ist mglich, indem Sie beim Instanziieren des Objekts
DateTime die entsprechenden Angaben machen:
Reichen diese direkten Berechnungen nicht aus, knnen Sie mit TimeSpan
Zeitspannen arbeiten. Diese werden aus der Struktur TimeSpan ab-
geleitet. Die Struktur kann als Datumswert in der folgenden Form
dargestellt werden:
[-]d.hh:mm:ss:ff
Der Konstruktor erwartet Ticks (ein Parameter), Zeiten (drei Para- TicksPerHours
meter f)r Stunde, Minute und Sekunde) oder vier (Tage plus Add
Subtract
Zeit). F)r Berechnungen sind auch ein paar Konstanten interes-
sant – in der TimeSpan-Struktur als Felder definiert – die die Ticks
pro Zeiteinheit enthalten: TicksPerHour f)r 1 Stunde, TicksPerMinute
f)r eine Minute usw. bis hin zu Zero f)r 0. Instanzen von TimeSpan
knnen direkt berechnet werden, dazu dienen die Methoden Add
und Subtract.
Mit diesen Angaben erfolgt nun die Berechnung. Das Ende der
ersten Lektion ist leicht zu ermitteln:
kurs = kurs.Add(lektion)
Alternativ zur Verwendung von Subtract zum Abziehen von Zei- Negate
ten knnen Sie das TimeSpan-Objekt auch mit der Methode Negate
negieren und Add verwenden.
Die Formatieranweisungen
Der einfachste Zugriff auf die Formatierung erfolgt mit der Metho- Individuelle
de ToString, die als Parameter eine Formatierungsanweisung be- Datumsformate
kommt:
heute.ToString("dd.MM.yyyy")
Einzelformate Die Liste der Einzelformate ist umfangreicher und erlaubt beliebi-
ge Kombinationen der einzelnen Bestandteile von Datum und
Zeit.
Sandini Bib
Datum und Zeit 293
Format Beschreibung
d, dd Tag ohne und mit f3hrender Null
ddd Kurzform des Wochentagsnamens (Fr)
dddd Langform des Wochentagsnamens (Freitag)
M, MM Monat ohne und mit f3hrender Null
MM Kurzform des Monatsnamens (Feb)
MMM Langform des Monatsnamens (Februar)
yy Jahr, zweistellig
yyyy Jahr, vierstellig
H, HH Stunden im 24–Stunden-Format ohne und mit f3hrender Null,
h, hh die kleinen Buchstaben erzeugen 12–Stunden-Format
m, mm Minute ohne und mit f3hrender Null
s, ss Sekunde ohne und mit f3hrender Null
tt AM oder PM
: Standardtrennzeichen f3r Zeitwert
/ Standardtrennzeichen f3r Datum, der Schrgstrich wird auf
einem deutschen Windows als Punkt erscheinen.
Beachten Sie die Backslashes, mit denen freier Text in die Forma-
tierung eingebaut wird:
Imports System.Globalization
Beachten Sie, dass f!r die Darstellung von asiatischen Schriftzeichen die
t entsprechenden Sprachpakete im Browser installiert sein m!ssen.
Der zweite Punkt d)rfte trivial sein. Generell ist es jedoch empfeh-
lenswert, dem Benutzer die Auswahl zu )berlassen und gleichzei-
tig eine »Vermutung« )ber seine Pr'ferenzen anzustellen.
Browser bieten die Mglichkeit, die bevorzugte Sprache einzustel-
len und )ber die Anforderung an den Server zu senden. Sicher
werden die meisten Benutzer davon nicht Gebrauch machen, aber
allein aufgrund der Standardeinstellungen d)rfte die Sprachaus-
wahl in den meisten F'llen korrekt sein.
Sprache im Die Einstellungen der Sprache erfolgen beim Internet Explorer
Internet Explorer )ber Extras | Internetoptionen. Dort kann auf der Registerkar-
te Allgemein die Option Sprachen angeklickt werden. Im fol-
genden Dialog Spracheinstellung finden Sie eine Liste von
Sprachen, beginnend mit einer Standardsprache am Anfang der
Liste und mehrerer anderer Eintr'ge. Der Browser kombiniert die
Sandini Bib
Globalisierung und Mehrsprachigkeit 297
in der Liste eingetragenen Werte und qualifiziert sie mit einer Ge-
wichtung, die von der Position abh'ngt. Der erste Eintrag hat im-
mer die Gewichtung 1 und definiert damit die Prim'rsprache.
tung mit dem Attribut q= ein, wobei der Parameter eine Gleit-
kommazahl mit maximal 3 Nachkommastellen zwischen 0
und 1 sein darf. Die Abstufung ist standardm'ßig in der Folge
(1, 0.5), (1, 0.7, 0.3), (1, 0.8, 0.5, 0.3) usw. definiert, wobei dies
ein browserspezifisches Verhalten darstellt. HTTP selbst legt
die Werte nicht fest. Letztlich bleibt es dem Benutzer )berlas-
sen, feinere Abstufungen vorzunehmen.
Wenn nun Ihre Seite eine derart feine Unterscheidung nicht ben-
tigt, weil nur grob die Sprachen unterschieden werden, bietet die
Art der Darstellung einen einfachen Fallback. Aus der Angabe
»de-CH« kann leicht die Stammsprache, hier »de« abgeleitet wer-
den, da diese immer vorn links und immer mit einem Binde- oder
Unterstrich getrennt ist. Es hat sich eingeb)rgert, die Landescodes
groß zu schreiben, ein Server, der solche Codes auswertet, sollte
jedoch nicht darauf vertrauen.
In .NET Im .NET-Framework wird die als »Kultur« bezeichnete Kombina-
tion aus Sprache und Land auf den Standards ISO 639-1 und ISO
3166 aufgebaut. Dabei wird der Sprachcode aus ISO 639-1 genom-
men (Version -2 bezeichnet den Code dreistellig), dann folgt im-
mer ein Bindestrich und dann der L'ndercode, wie er in ISO 3166
festgelegt ist. Sprachen knnen dar)berhinaus mehrere Schriftsys-
teme verwenden. So ist Serbisch sowohl mit lateinischen als auch
kyrillischen Schriftzeichen darstellbar. Hier wird vor dem Sprach-
code noch ein Pr'fix davorgesetzt – »Cy« f)r Kyrillisch und »Lt«
Sandini Bib
Globalisierung und Mehrsprachigkeit 299
Bei der Programmierung stellt sich nun die Frage, wie man die
Sprachcodes ermitteln kann.
Wie es Die Kollektion f)r die Sprachcodes heißt UserLanguages. Der Index
funktioniert 0 enth'lt immer die Standardsprache:
sprache.Text = Request.UserLanguages(0)
Alle weiteren Indizes enthalten dann die Angaben, wie sie vom
Browser gesendet werden. Die Auswertung der Qualifizierung
m)ssen Sie selbst vornehmen.
Abbildung 4.35: Ausgabe der Sprachangaben, die der Browser gesendet hat
Wenn Sie eine solche Liste empfangen, w're es sinnvoll, dem Be-
nutzer eine Auswahlmglichkeit zu )berlassen und zugleich den
Standardwert entsprechend zu setzen. Das folgende Beispiel zeigt,
wie dies erfolgen kann. Zur Ausgabe der Auswahlliste wird das
Server-Steuerelement RadioButtonList verwendet:
<h1>Sprachauswahl</h1>
Bitte wWhlen Sie die Sprache fSr diese Website
<form id="BrowserLanguages" method="post" runat="server">
<asp:RadioButtonList Runat="server" ID="sprachauswahl"/>
<input type="submit" value="Ihre Auswahl"/>
</form>
<br/>
Ihre Auswahl: <asp:Label Runat="server" ID="auswahl"/>
Listing 4.36: Einfachste Form einer benutzerabh(ngigen Sprachauswahl
(BrowserLanguages.aspx)
Sandini Bib
Globalisierung und Mehrsprachigkeit 301
Wie es Im Beispiel wird eine Liste von Sprachen vorbereitet, die die Seite
funktioniert darstellen kann. Diese Liste wird in der Methode SetLanguageTable
aufgebaut. Zum Einsatz gelangt hier der Typ Hashtable, mit dem
einfache Schl)ssel/Werte-Paare dargestellt werden knnen. Sie
knnen so die Sprachcodes als Schl)ssel verwalten und als Werte
die Ausgabe f)r den Benutzer steuern.
Die eigentliche Arbeit wird in Page_Load erledigt. Zuerst wird fest-
gestellt, ob das Formular das erste Mal aufgebaut wurde. Die Ab-
frage der Daten muss nur dies eine Mal erfolgen, nachfolgende
Aufrufe behalten die Darstellung )ber den Anzeigestatus der Seite:
If Not Page.IsPostBack Then
Kollektion der Dann wird die Hashtable-Instanz ht aufgebaut. Nun kann die Kol-
Sprachen lektion der im Browser des Benutzers definierten Sprachen durch-
laufen werden:
Sprachcode Nun ist die Pr'sentation einer Auswahl auf Basis der Browserein-
ermitteln stellungen nat)rlich nur sinnvoll, wenn dies Ihre Site auch unter-
st)tzt. Deshalb wird in ht nachgeschaut, ob die Sprache auch defi-
niert wurde:
If ht.Contains(langcode) Then
Ist das der Fall, wird eine zweite Liste aufgebaut, die nun eine
Schnittmenge der Daten aus dem Browser und der vom Server ak-
zeptierten enth'lt. Vermutlich ist diese Menge in der Praxis sehr
klein, deshalb kommt der Typ ListDictionary zum Einsatz, der auf
kleine Auflistungen bis 16 Elemente spezialisiert ist. Beachten Sie
hier noch, dass die Definition aus dem Namensraum System.
Collections.Specialized stammt. Mit dem Hinzuf)gen der passen-
den Elemente entsteht die Datenliste f)r die Optionsfelder:
Sandini Bib
Globalisierung und Mehrsprachigkeit 303
ld.Add(langcode, ht(langcode))
Nun wird die fertige Liste dem Steuerelement zugewiesen: Liste der Sprachen
sprachauswahl.DataSource = ld
Bei Optionsfeldern sind nun noch die Datenquellen f)r die Felder
(value-Attribut) und der anzuzeigende Text zu definieren. Dazu
werden die reservierten Wrter »Key« bzw. »Value« verwendet:
sprachauswahl.DataValueField = "Key"
sprachauswahl.DataTextField = "Value"
sprachauswahl.DataBind()
Zuletzt wird noch die Auswahl auf den ersten Wert gesetzt:
sprachauswahl.SelectedIndex = 0
Im Else-Zweig wird, wenn der Benutzer seine Auswahl getroffen Auswahl der
hat, der Code der Auswahl angezeigt. Diese Information w)rde in Sprache
der praktischen Anwendung zur Steuerung der Seite herangezo-
gen werden, beispielsweise zur Selektion der passenden Nach-
richten aus einer Datenbank:
auswahl.Text = sprachauswahl.SelectedItem.Value
CultureInfo Die praktische Umsetzung nutzt die Klasse CultureInfo aus dem
Namensraum System.Globalization. Dies wurde in Abschnitt
4.10.1, »Grundlagen der Globalisierung« ab Seite 294 bereits dar-
gestellt. Nun gilt es die im letzten Beispiel gezeigte Applikation
tats'chlich mehrsprachig zu programmieren. Dazu wird zuerst
aus der Benutzerauswahl die Kultur ermittelt (sprachauswahl ist
das RadioButtonList-Steuerelement):
Thread.CurrentThread.CurrentCulture = MyCulture
<h1>Sprachauswahl</h1>
Bitte whlen Sie die Sprache fr diese Website
<form id="BrowserLanguages" method="post" runat="server">
<asp:RadioButtonList Runat="server" ID="sprachauswahl"/>
<input type="submit" value="Ihre Auswahl"/>
<br/>
Ihre Auswahl: <asp:Label Runat="server" ID="auswahl"/>
<br/>
Whrung: <asp:Label Runat="server" ID="waehrung"/>
<br/>
Kalender: <asp:Calendar Runat="server" ID="kalender"/>
</form>
Listing 4.38: Sprachauswahl und deren Auswirkung auf Ausgaben
(BrowserLanguagesCulture.aspx)
Die Code-Datei steuert nun zum einen den Aufbau der Liste der
Optionsfelder, zum anderen die Reaktion der Ausgaben durch
Verndern der aktuellen Kultur. Zu beachten ist hierbei, dass nur
»echte« Kulturangaben verwendet werden k&nnen.
Ein »Fallback«-Pfad, wie in Abbildung 4.34 gezeigt, ist mit der stati-
schen Methode CreateSpecificCulture nutzbar. Kulturen, die nicht voll-
st#ndig aufgel$st sind, wie beispielsweise »fr«, werden als invariant be-
t
zeichnet. Vollst#ndig w#re »fr-ch« (Franz$sisch in der Schweiz) usw.
Abbildung 4.37: Darstellung einer W/hrungsangabe und eines Kalenders in drei Kultur-
formen (1sterreich, USA und Frankreich)
Kalender definieren den Begriff der :ra. Der bei uns verwen-
dete Gregorianische Kalender kennt zwei :ren: vor Christus
und nach Christus. Die :ra nach Christus beginnt mit dem
Jahr 1 und zhlt die Jahre fortlaufend, bis heute sind es 2002.
Die Implementierung in .NET verarbeitet allerdings nur die
aktuelle :ra. :hnlich funktioniert das auch beim hebrischen
Sandini Bib
Globalisierung und Mehrsprachigkeit 307
Kalender, der nur die aktuelle :ra verarbeiten kann, das sind
dort die Jahre 5343 bis 6000 (entspricht 1582 bis 2240 im grego-
rianischen Kalender). Auch dieser Kalender hat 12 Monate,
im Gegensatz zu unserer Zhlung schwankt aber Anzahl der
Tage im Monat Cheschwan (2) und Kislew (3) je nach Lage
der j1dischen Feiertage. Dar1ber hinaus gibt es statt eines
Schalttags im Schaltjahr einen ganzen Schaltmonat. Einfacher
ist der koreanische Kalender, der hnlich dem unsrigen auf-
gebaut ist. Lediglich die Jahreszahl ist anders definiert. Das
Jahr 2002 bei uns entspricht in Korea dem Jahr 4335.
Die Klasse Calendar ist abstrakt. Sie k&nnen daraus eigene Kalen-
der entwickeln oder eine der fertigen Ableitungen verwenden.
Das folgende Beispiel lsst die Auswahl von einem aus drei Ka-
lendern zu:
<h1>Kalender</h1>
Whlen Sie Ihren Kalender / Choose your calendar:
<form id="GlobalizationCalendars" method="post"
runat="server">
<asp:RadioButtonList Runat="server" É
ID="calendarselect" É
AutoPostBack="True">
<asp:ListItem Runat="server" Selected="True" É
Value="greg">Gregorianisch</asp:ListItem>
<asp:ListItem Runat="server" Selected="False" É
Value="korea">Koreanisch</asp:ListItem>
<asp:ListItem Runat="server" Selected="False" É
Value="hebrew">Hebrisch</asp:ListItem>
</asp:RadioButtonList>
Das aktuelle Jahr in diesem Kalender ist:
<asp:Label Runat="server" ID="calendar"/>
</form>
Listing 4.40: Auswahl eines Kalenders und Anzeige der Jahreszahl dieses Kalenders
(GlobalizationCalendars.aspx)
Sandini Bib
308 4 Die Basisklassen des Frameworks
If (Page.IsPostBack) Then
Dim ca As System.Globalization.Calendar = Nothing
Dim dt As System.DateTime = System.DateTime.Now
Select Case calendarselect.SelectedItem.Value
Case "greg"
ca = New System.Globalization.GregorianCalendar()
calendar.Text = ca.GetYear(dt).ToString()
Case "korea"
ca = New System.Globalization.KoreanCalendar()
calendar.Text = ca.GetYear(dt).ToString()
Case "hebrew"
ca = New System.Globalization.HebrewCalendar()
calendar.Text = ca.GetYear(dt).ToString()
End Select
End If
End Sub
Listing 4.41: Nutzung von fertigen Kalendern zur Datumsdarstellung (Globalization-
Calendar.aspx.vb)
Wie es Der Einfachheit halber wird hier die Variable ca als Typ Calendar
funktioniert angelegt:
Dim ca As System.Globalization.Calendar = Nothing
Kalender erzeugen Je nach Auswahl wird dann der passende Kalender erzeugt:
ca = New System.Globalization.HebrewCalendar()
calendar.Text = ca.GetYear(dt).ToString()
Der Umgang damit ist relativ unkritisch. Die Reaktion des Pro-
gramms zeigt die nchste Abbildung.
Sandini Bib
Globalisierung und Mehrsprachigkeit 309
Das einfachere Prinzip besteht darin, jede Vorlage, also die aspx- Prinzipien der
Dateien, f1r jede Sprache neu zu schreiben. Der hinterlegte Code Ressourcen-
Dateien
sollte identisch bleiben. Dies ist praktikabel, wenn der Textanteil
sehr groß ist und sich die Art und Weise der Gestaltung der Texte
von Sprache zu Sprache stark unterscheidet. So kommt es hufig
vor, dass deutsche W&rter sehr viel lnger sind als ihre englischen
Sandini Bib
310 4 Die Basisklassen des Frameworks
;file culture.de.txt
title=Lokalisierte Texte in ASP.NET
langcode=Aktuell wurde folgender Code ausgewhlt
date=In dieser Sprache sieht das Datum folgendermaßen aus
Dateinamen Der Dateiname ist frei whlbar, sollte jedoch einem bestimmten
Schema folgen, damit Sie tatschlich mit mehreren Sprachen ar-
beiten k&nnen. Notwendig ist eine Standarddatei, beispielsweise
»culture.txt«. Darauf folgen die landesspezifischen Formen,
»culture.de.txt«, »culture.en.txt«. In einem weiteren Konvertie-
rungsschritt entsteht daraus die resources-Datei, die die Daten
binr speichert.
Das resx-Format Es gibt statt dieser Textdarstellung auch die M&glichkeit, das resx-
Format zu verwenden, ein einfaches XML-Format. Die Namens-
vergabe funktioniert hnlich wie bei den Textdateien, auch hier
muss als Endung .resx verwendet werden, um die Bedeutung der
Datei zu unterstreichen. In einem weiteren Konvertierungsschritt
entsteht daraus die resources-Datei, die die Daten binr speichert.
Aus der Schemadefinition am Anfang der Datei lsst sich die Ge- Aufbau der Datei
staltungsbreite der Tags ableiten. Generell wird jeder Datenwert
in einem Element <data> gehalten. Darin sind ein oder mehrere
Elemente vom Typ <value>, die Zeichenketten enthalten. Zulssige
Attribute f1r <data> sind:
E name
Hiermit erfolgt die Angabe des Namens f1r diesen Ressource-
wert. Dies ist der Schl1ssel, um den Text spter auf der Seite
zuordnen zu k&nnen.
E type
Hier k&nnen Sie den Datentyp des Wertes festlegen, wenn er
keine Zeichenkette darstellt. Sie m1ssen den Typ vollstndig
und mit Angabe der Assembly schreiben, beispielsweise
type="System.Int32, mscorlib".
E mimetype
F1r die Speicherung von Bildern oder binren Daten sollten
Sie den MIME-Typ angeben. Der MIME-Typ image/png weist
darauf hin, dass die Daten als Binrdaten eines PNG-Bildes zu
interpretieren sind.
Aus den Attributen lsst sich schon ableiten, dass die Ressource-
Dateien im XML-Format flexibler sind. Denn in modernen Web-
seiten kommen hufig Bilder zum Einsatz, die Texte enthalten.
Sandini Bib
312 4 Die Basisklassen des Frameworks
Abbildung 4.39: Aufbau der Quellverzeichnisse und der Textdatei f$r die automatische
Erstellung von Ressourcen
Bin re Daten in Das Einbetten binrer Daten ist freilich nicht ganz einfach. Das
Ressource-Dateien Framework bietet aber auch hierzu alle denkbaren Hilfsmittel.
Wenn Sie mit sehr vielen Ressourcen arbeiten, bietet sich folgen-
der Weg an:
Ressourcen- In der Praxis hat sich freilich gezeigt, dass die so erstellten Dateien
Dateien recht m1hevoll zu bearbeiten sind. Oft werden Texte von externen
automatisch
erstellen Jbersetzern angefertigt und Bilder von Grafikern entworfen. Eine
»automatische« Entnahme aus einem Verzeichnis erscheint sinn-
voller. Es gibt nun auch daf1r zwei Wege. Zum einen k&nnen Sie
resx-Dateien erstellen (das ist das XML-Format) und diese dann
mit dem Kommandozeilenwerkzeug resgen in binre Ressourcen-
Dateien konvertieren. Dasselbe Werkzeug kann binre Dateien,
die dann die Dateierweiterung .resources tragen m1ssen, wieder
zur1ck in resx-Dateien umwandeln. F1r ein eigenes Programm ist
es nat1rlich sinnvoll, gleich das binre Format zu erstellen. Die
Laufzeitumgebung, die spter die Dateien in Abhngigkeit von
der Benutzerwahl verwendet, kann nur mit dem binren Format
umgehen. Dies dient vor allem h&chster Effizienz. Das stndige
Parsen von XML-Dateien wre bei einem hochbelasteten Server
nicht vertretbar.
System.Resources Zum Erstellen und Verwenden von Ressourcen-Dateien dient der
folgende Namensraum:
System.Resources
stammverzeichnis.DataBind()
End If
End Sub
End Class
Listing 4.44: Programm zum Erstellen von bin/ren resources-Dateien (Globalization-
GetResource.aspx.vb)
Wie es Beim ersten Aufruf wird der Else-Zweig ausgef1hrt. Hier wird
funktioniert das aktuelle Verzeichnis gelesen und eine Liste aller Unterver-
zeichnisse in einem DropDownList-Element angezeigt:
di = New DirectoryInfo(Server.MapPath("."))
stammverzeichnis.DataSource = di.GetDirectories()
di = New DirectoryInfo (É
Server.MapPath (stammverzeichnis.SelectedItem.Value))
Sandini Bib
Globalisierung und Mehrsprachigkeit 317
Beim Zugriff auf die Textdatei wird erwartet, dass diese nach
dem Muster »Schl1ssel=Wert« aufgebaut ist. Geeignet f1r solche
Zugriffe ist der StreamReader.
Die Datei wird solange gelesen, bis keine Daten mehr verf1gbar
sind:
sFile = sr.ReadLine()
Kontrolle mit Damit ist das Programm auch schon fertig. Die Dateien liegen
resgen nun bereits als direkt verwendbare Ressourcen-Dateien vor. Zur
Kontrolle bietet es sich an, diese mit resgen in lesbare XML-Datei-
en umzuwandeln. Dazu gehen Sie folgendermaßen vor:
1. Iffnen Sie die Visual Studio .NET Konsole 1ber Start | Alle
Programme | Microsoft .NET Framework SDK | Micro-
soft Visual Studio .NET | Visual Studio .NET Tools | Vi-
sual Studio .NET Befehlszeile.
2. Wechseln Sie in das Verzeichnis, in dem die .resources-Dateien
liegen.
3. Geben Sie Folgendes ein:
resgen culture.de.resources culture.de.resx
:ndern Sie die Namen entsprechend den tatschlichen Bedin-
gungen. Die Dateierweiterungen m1ssen zwingend verwendet
werden.
Sie k&nnen hier gut erkennen, wie die Datentypen und der MIME-
Typ eingerichtet wurde. Ein Blick in die XML-Daten selbst ist nur
wenig mehr aufschlussreich, zeigt jedoch klar, welche m1hevolle
Arbeit das kleine Hilfsprogramm hier abgenommen hat.
Sandini Bib
Globalisierung und Mehrsprachigkeit 319
Abbildung 4.43: Ausschnitt aus der erzeugten resx-Datei mit Text- und Bilddaten
Vor den ersten Versuchen sollten Sie sich dar1ber im Klaren sein,
wie Ihre Vorlagen mit Daten versorgt werden. Sie k&nnen prinzi-
piell jedes HTML-Element zu einem serverseitigen Steuerelement
machen, ohne sich 1ber die Funktionsweise dahinter Gedanken ma-
chen zu m1ssen. Das f1hrt dann zu folgendem Code im HTML-Teil:
rm = ResourceManager.CreateFileBasedResourceManager É
("culture", Server.MapPath("resource"), Nothing)
Sandini Bib
320 4 Die Basisklassen des Frameworks
Der Dateiname, nach dem gesucht wird, setzt sich aus dem Prfix
(erstes Argument der statischen Methode CreateFileBasedResource
Manager), dem Sprachcode oder einem davon abgeleiteten Fall-
back-Wert der aktuellen Kultur und der Dateierweiterung
resources zusammen, jeweils durch Punkte getrennt.
title.InnerHtml = rm.GetString("title")
Die hier vorgestellte Technik hat den Vorteil, dass die sprach-
lichen Fragmente außerhalb der Gestaltung und auch außerhalb
des Codes liegen. :ndern Sie die Ressourcen-Dateien, ndert sich
der Inhalt der Seiten sofort. Rechtschreibkorrekturen ben&tigen
nun weder Code- noch Layout-Eingriffe. Gerade bei komplizierte-
ren Seiten ist dies ein enormer Vorteil.
Dar1ber hinaus sind die Zugriffe auf die Ressourcen auf eine Da-
tei beschrnkt. Diese Datei bleibt permanent ge&ffnet, sodass auch
dies ein Leistungsvorteil darstellt. Allerdings haben Sie bei laufen-
dem Betrieb keine Chance, auf die Ressourcen-Datei zuzugreifen,
weil sie gesperrt ist. Wenn Sie erzwingen m&chten, dass die Datei
immer geschlossen wird, schreiben Sie folgenden Code ans Ende
des Programms:
rm.ReleaseAllResources()
Abbildung 4.44: Die Anzeige der Texte folgt der Vorgabe des Benutzers im Browser.
Response.Write ("<a
href=""GlobalizationUseResourceImg.aspx""> É
GlobalizationUseResourceImg.aspx</a>")
Else
' Start programm
Response.ContentType = "image/jpeg"
Thread.CurrentThread.CurrentUICulture É
= CultureInfo.CreateSpecificCulture
(Request.UserLanguages(0))
Dim rm As ResourceManager É
=
ResourceManager.CreateFileBasedResourceManager("culture",É
Server.MapPath("resource"),Nothing)
Dim img As System.Drawing.Image = CType(rm.GetObject( É
Request.QueryString("image")), É
System.Drawing.Image)
Response.ClearContent ()
img.Save (Response.OutputStream, ImageFormat.Jpeg)
Response.End ()
rm.ReleaseAllResources ()
End If
End Sub
</script>
Listing 4.48: Auslieferung eines Bildes aus der Ressourcen-Datei
(GlobalizationUseResourceImgSource.aspx)
Der Zugriff auf die Ressource entspricht dem bereits f1r Text ge- Wie es
zeigten Programm. Einzige Ausnahme bildet die Verwendung der funktioniert
Der Abruf erfolgt nun aber nicht mit GetString, sondern mit
GetObject. Erzeugt wird wieder das urspr1ngliche Bild, basierend
auf der Auswahl des GET-Parameters:
System.Drawing.Image img = É
CType(rm.GetObject(Request.QueryString("image"), É
System.Drawing.Image)
Sandini Bib
324 4 Die Basisklassen des Frameworks
Damit der Browser mit den Daten etwas anzufangen weiß, ist der
HTTP-Header Content-Type entsprechend zu setzen:
Response.ContentType = "image/jpeg"
Response.ClearContent ()
Response.End ()
Wenn Sie nun mit Ressourcen arbeiten, wird f1r jede Kultur eine
so genannte Satellitenassembly erstellt. Die Fallback-Ressource
landet in der Hauptassembly. Mit Visual Studio .NET ist das sehr
einfach. Die entsprechenden Compiler-Anweisungen werden au-
tomatisch verwendet, wenn Ressourcen-Dateien hinzugef1gt wer-
den. Dazu gehen Sie folgendermaßen vor:
Sandini Bib
Globalisierung und Mehrsprachigkeit 325
Nach der Jbersetzung des Projekts legt Visual Studio .NET unter-
halb /bin f1r jede Kultur ein Unterverzeichnis an und platziert
dort die entsprechende DLL. Verwenden k&nnen Sie diese nun in
Ihrem Code nach folgendem Schema:
Imports System.Resources
Imports System.Reflection
Imports System.Globalization
Imports System.Collections
Imports System.ComponentModel
Imports System.Drawing
Achtung, Eine Falle stellt die Angabe des Prfixes dar. Sie m1ssen hier den
Namensraum Namensraum Ihrer Applikation mit angeben, andernfalls findet
angeben!
der Ressourcenmanager die Ressource in der Hauptassembly
nicht:
Addison.VBNet.Basis.culture
Wenn Sie nicht mit Visual Studio .NET arbeiten, k$nnen Sie selbstver-
st#ndlich auch Ressourcen-Dateien in Satellitenassemblies verpacken.
Nutzen Sie das Werkzeug al (Assembly Linker) zum Verbinden der Sa-
telliten mit der Hauptassembly und die Option /res des Compilers vbc
beim Bbersetzen der Hauptdatei. Außerdem m0ssen Sie die fertigen
Assemblies selbst in die entsprechenden Verzeichnisse kopieren
(/bin/<cultur>).
Sandini Bib
Globalisierung und Mehrsprachigkeit 327
Praxistipps
In der Praxis m1ssen Sie, bevor aufwndige Lokalisierungen er- Vor der
folgen, ein paar Fragen beantworten: Entwicklung der
Ressourcen
E Wer 1bersetzt die Texte?
E Wer 1bersetzt Bilddaten?
E Passt die Gestaltung zu allen Sprachen?
E Liegen auch Artikel- oder Inhaltsdaten in den passenden Spra-
chen vor?
E Wie gehen Sie mit Sprachanforderungen um, f1r die Sie keine
Jbersetzung haben?
E Beherrschen Sie die Aktualisierung Ihrer Applikation noch,
wenn Sie viele Sprachen haben?
Sub Application_Start ()
Application ("AllRecourses") É
= System.Resource.ResourceManager.É
CreateFileBasedResourceManager("culture", É
Server.MapPath("resource"), Nothing)
End Sub
Listing 4.50: Laden des Ressourcen-Managers beim Start der Applikation
Die Auswahl der Kultur muss nun nat1rlich noch an die Sitzung
gekoppelt werden, denn dieser Vorgang ist f1r jeden Benutzer in-
dividuell:
Innerhalb Ihrer Seiten m1ssen Sie nun noch Zugriff auf die bereits
geladenen Ressourcen erhalten. Dazu wird, vorzugsweise in der
Methode Page_Init, folgender Code verwendet:
Dim rm As ResourceManager É
= CType(Application("AllResources"), ResourceManager)
E requestEncoding
Bestimmt die Kodierung, die ASP.NET f1r eingehende Anfra-
gen erwartet. Der Standard ist UTF-8.
Sandini Bib
Zugriff auf das Dateisystem 329
E responseEnconding
Bestimmt die Kodierung der gesendeten Daten. Der Standard
ist UTF-8.
E fileEncoding
Wenn Dateien ohne explizite Angabe einer Kodierung ge-
schrieben werden, bestimmt dieser Parameter die Einstellung.
Der Standard ist UTF-8.
E culture
Bestimmt die Kultur in der Form »de-DE«, wie im Abschnitt
weiter oben beschrieben.
E uiCulture
Bestimmt die Kultur die Steuerelemente bei der Ausgabe ver-
wenden, wenn Ressource-Dateien eingesetzt werden.
4.11.1 Einfhrung
Einige Einsatzbeispiele, wof1r Zugriffe auf das Dateisystem erfor-
derlich sein k&nnen, sind:
E Protokolldateien
Protokollieren Sie Vorgnge in Ihrer Applikation in eine Text-
datei.
E Ablage von Formulardaten
Legen Sie den Inhalt eines Formulars als Textdatei ab.
E News und Tipp des Tages
Zeigen Sie auf Ihrer Website News an, die Sie als Text- oder
HTML-Datei auf dem Server ablegen.
Sandini Bib
330 4 Die Basisklassen des Frameworks
Imports System.IO
E Directory, DirectoryInfo
Diese Klassen erlauben den Zugriff auf Verzeichnisse 1ber sta-
tische Methoden und enthalten Informationen 1ber ein Ver-
zeichnis.
E Path
Path dient der Berechnung und Manipulation von Pfaden, wo-
bei in den meisten Fllen nicht reflektiert wird, ob der Pfad
wirklich existiert.
E File, FileInfo
Diese Klassen erlauben den Zugriff auf Dateien 1ber statische
Methoden und enthalten Informationen 1ber eine Datei.
E StreamReader, StreamWriter, BinaryReader, BinaryWriter
Lesen und Schreiben von Textdaten bzw. Binrdaten aus bzw.
in Dateien.
geben werden kann. Ist der Pfad vorhanden, wird eine Liste der
Verzeichnisse und Dateien darin angezeigt. Das folgende Beispiel
nutzt bereits die Datenbindungssyntax, statt einer Datenbank
kommen hier Dateilisten zur Anzeige. Eine ausf1hrliche Erkl-
rung folgt im Zusammenhang mit der Ausgabe von Daten. Eben-
so gelangen bereits einige Server-Steuerelemente zum Einsatz.
Zum Verstndnis des Datei- und Verzeichniszugriffs sind genaue
Kenntnisse dar1ber nicht notwendig.
<body MS_POSITIONING="GridLayout">
<form id="FileReadDir" method="post" runat="server">
<asp:textbox runat="server" id="Verzeichnisname"/>
<asp:button runat="server" id="senden" text="Anzeigen"/>
</form>
<h2>Verzeichnisse</h2>
<asp:Repeater Runat="server" ID="Verzeichnisse">
<ItemTemplate>
<%# Container.DataItem.Name %>
<br/>
</ItemTemplate>
</asp:Repeater>
<h2>Dateien</h2>
<asp:Repeater Runat="server" ID="Dateien">
<ItemTemplate>
<%# Container.DataItem.Name %>
(<%# Container.DataItem.Length %>
Bytes)
<br/>
</ItemTemplate>
</asp:Repeater>
<asp:Label Runat="server" ID="Ausgabe"/>
</body>
Listing 4.52: Formular zur Anzeige von Verzeichnisinformationen (FileReadDir.aspx)
Wie es Beim Zugriff auf Verzeichnisse tritt oft das Problem auf, dass der
funktioniert Pfad nicht gefunden werden kann oder die Zugriffsrechte nicht
ausreichend sind. Um robuste Applikationen zu schreiben, sollten
die Ausnahmen abgefangen werden, die die Klassen erzeugen.
Ideal ist daf1r die Try-Catch-Anweisung. Der Try-Zweig wird zu-
erst ausgef1hrt, bis eine Ausnahmebedingung auftritt.
Sandini Bib
Zugriff auf das Dateisystem 333
Verzeichnisse.DataSource = dinfo.GetDirectories()
Verzeichnisse.DataBind()
Dateiinformationen setzen voraus, dass ein Zugriff auf eine Datei Dateiinforma-
vorliegt. Mit der Methode GetFiles erhalten Sie eine Kollektion tionen
Dateien.DataSource = dinfo.GetFiles()
Falls die Anzeige des Verzeichnisses misslingt, wird eine Ausnah- Fehler abfangen
me vom Typ DirectoryNotFoundException erzeugt. Mit Catch k&nnen
Sie diese abfangen:
Interessant ist eventuell die Fehlermeldung, die die Klasse hier er-
zeugt:
ausgabe.Text += nichtgefunden.Message
Eigenschaft Bedeutung
GetDirectories Gibt eine Kollektion der enthaltenen Verzeichnisse
zurck:
E GetDirectories(pfad)
E GetDirectories(pfad,platzhalter)
Eigenschaft Bedeutung
GetParent Name des bergeordneten Verzeichnisses
CreateDirectory Erzeugt ein Verzeichnis
SetDirectory Setzt das aktuelle Verzeichnis
Move Verschiebt ein Verzeichnis mit dem gesamten Inhalt:
E Move(pfad_quelle, pfad_ziel)
Eigenschaft Beschreibung
Attributes Attribute
CreationTime Datum der Erzeugung
FullName Pfad und Name
Parent 6bergeordnetes Verzeichnis
Root Stammverzeichnis
Dateiattribute Die Attribute sind eine Aufzhlung mit dem Namen FileAttributes.
Diese Aufzhlung ist intern ein Bitfeld. Die Erkennung eines spe-
zifischen Attributes kann durch die Formel Attribut & FileAttribu-
tes.AttributName erfolgen. Das im letzten Beispiel gezeigte Pro-
gramm kann leicht um eine Auswertung der Attribute erweitert
werden. Sie finden das komplette Programm unter dem Namen
FileReadDirAttr.aspx. Nachfolgend die Erweiterung gegen1ber
dem letzten Beispiel:
Wie es Der Zugriff aus der Vorlage heraus ist etwas trickreich, soll hier
funktioniert aber exemplarisch gezeigt werden. Sie k&nnen in der Datenbin-
dungssyntax nat1rlich Methoden oder Eigenschaften vorhande-
ner Klassen verwenden. Sie k&nnen aber keine Instanzen erzeu-
gen. Das setzt voraus, dass Methoden direkt, ohne Instanziierung
verwendbar sein m1ssen. Dies wird im Beispiel mit dem Schl1s-
selwort Shared erreicht. Der Aufruf – mit vollstndiger Referenzie-
rung des Namensraumes – erfolgt in der HTML-Vorlage folgen-
dermaßen:
<%#
Addison.VBNet.Basis.MyFileInfo.ShowAttributes É
(Container.DataItem.Attributes)
%>
Lesen Sie diesen Ausdruck von innen nach außen. Zuerst erfolgt
der Zugriff auf den Container und dort auf das aktuelle Element
mit DataItem. Dann wird der Typ mit (System.IO.FileInfo) fest-
gelegt. Von diesem Objekt wird nun die Eigenschaft Attributes ab-
gerufen, die ein Objekt vom Typ FileAttributes zur1ckgibt. Dieses
Sandini Bib
Zugriff auf das Dateisystem 337
Methode Beschreibung
Create Verzeichnis bzw. mehrere Unter-
CreateSubdirectory verzeichnisse erzeugen
Delete Verzeichnis l3schen
MoveTo Verzeichnis verschieben:
E MoveTo (ziel)
Methode Bedeutung
GetAttributes Aufz#hlung der Dateiattribute
Get<XXX>Time Ermittelt (Get) bzw. setzt (Set) die Dateizeiten,
Set<XXX>Time wobei fr <XXX> Folgendes stehen kann:
E Creation – Datum der Erzeugung
E LastAccess – Datum des letzten Zugriffs
E LastWrite – Datum des letzten Schreibvorgangs
Methode Bedeutung
Move Verschiebt eine Datei mit dem gesamten Inhalt:
E Move(quelle, ziel)
Eine Instanz der Klasse FileInfo erlaubt den Zugriff auf Datei- FileInfo
informationen:
Eigenschaft Beschreibung
Attributes Attribute
CreationTime Datum der Erzeugung
FullName Pfad und Name
Name Dateiname
Parent 6bergeordnetes Verzeichnis
Length Gr3ße der Datei in Byte
Root Stammverzeichnis
Methode Beschreibung
Create Datei erzeugen
CreateText Datei und StreamWriter darauf erzeugen
Delete Datei l3schen
MoveTo Datei verschieben:
E MoveTo(pfad_ziel)
Try
// Versuche Zugriff
Catch Ausnahmevariable As Ausnahmetyp)
// Behandle Ausnahme
Catch (Andere_Ausnahmevariable As Anderer_Ausnahmetyp)
// Behandle andere Ausnahme
Finally
// Aktionen, die immer ausgefhrt werden sollen
End Try
Der Finally-Teil ist optional. Hier platzieren Sie Code, der immer
ausgef1hrt werden soll, egal ob eine Ausnahme auftrat oder nicht.
Um nun eine spezifische Ausnahme abfangen und behandeln zu
k&nnen, m1ssen Sie die Art des Fehlers entsprechend definieren:
Sandini Bib
Zugriff auf das Dateisystem 341
catch e As DirectoryNotFoundException
Diese Zeile f1hrt dazu, dass der Fehler »Verzeichnis nicht gefun-
den« abgefangen wird. Das Fehler-Objekt vom Typ DirectoryNot
FoundException wird in e gespeichert. Bevor Sie jedoch feink&rnige
Fehlerbehandlungen schreiben, m1ssen Sie die im aktuellen Kon-
text m&glichen Ausnahmen kennen:
Imports System.Security
<html>
<head>
<title>Protokolldatei</title>
</head>
<body>
<h3>Ausgabe einer Protokolldatei</h3>
<pre><asp:label runat="server" id="ausgabe"/></pre>
</body>
</html>
Listing 4.55: Ausgabe von Protokollinformationen (FileLog.aspx)
Imports System
Imports System.Web
Imports System.Web.UI
Imports System.Web.UI.WebControls
Imports System.Web.UI.HtmlControls
Imports System.IO
Imports System.Security
Catch e As DirectoryNotFoundException
ausgabe.Text = "<span style=""color:red""> É
Verzeichnis nicht vorhanden: "
ausgabe.Text += e.Message + "</span>"
Catch e As UnauthorizedAccessException
ausgabe.Text = "<span style=""color:red""> É
Kein Zugriff: "
ausgabe.Text += e.Message + "</span>"
End Try
End If
End Sub
End Class
Listing 4.56: Programm zum Schreiben und Lesen einer Protokolldatei (FileLog.aspx.vb)
Das Programm beginnt mit der Festlegung des Pfades. Die Pro- Wie es
tokolldatei soll innerhalb der Webapplikation gespeichert werden. funktioniert
Aus Sicht des Frameworks ist das Stammverzeichnis %system
root%\system32. Dass es sich um eine Webapplikation handelt, ist
erstmal nicht bekannt. Schließlich werden dieselben Klassen auch
in der Windows-Programmierung verwendet. In Abschnitt 8.2,
»Die Welt der Standardobjekte« ab Seite 747 werden die Klassen
vorgestellt, die in ASP.NET den Zugriff auf den Webserver erlau-
ben. Dazu geh&rt auch Server. Diese Klasse enthlt eine Methode
MapPath, die einen lokalen oder virtuellen Pfad einer Webapplika-
tion in eine physische Pfadangabe umwandelt:
Dann wird der Eintrag, der das Protokoll f1llen soll, erzeugt. Ver-
wendet wird hier die IP-Adresse des Browsers und das aktuelle
Datum einschließlich der Zeit:
If File.Exists(log) Then
Jetzt kann jetzt der Eintrag hinzugef1gt werden. Dazu wird ein
StreamWriter-Objekt erzeugt:
logs.WriteLine(logeintrag)
Sandini Bib
344 4 Die Basisklassen des Frameworks
Dann wird die Datei geschlossen und zur Kontrolle angezeigt. Die
Vorstellung der Anzeigefunktion ShowFile erfolgt weiter unten.
Sie sollten Dateien immer explizit und so schnell wie m$glich schließen.
t In Mehrbenutzerumgebungen f0hren offene Dateien zu Fehlern oder
Leistungseinbußen. Vertrauen Sie nicht darauf, dass offene Dateien am
Ende der Seite sofort automatisch geschlossen werden, auch wenn dies
beispielsweise in einer Testumgebung der Fall sein d0rfte.
Falls die Datei noch nicht existierte, wird der zweite Teil der If-
Then-Anweisung ausgef1hrt. Der einzige Unterschied besteht da-
rin, dass statt AppendText zum Anhngen an die Datei mit Create
Text eine neue Textdatei erzeugt wird:
Catch e As DirectoryNotFoundException
Catch e As UnauthorizedAccessException
5 Grundlagen der
Datenspeicherung
5.1 Schnellstart
Dieser Abschnitt gibt einen kompakten Jberblick 1ber das Thema
und zeigt sinnvolle Verkn1pfungen mit ergnzenden und vor-
bereitenden Kapiteln. Der Wegweiser in die Referenz hilft, die pas-
senden Seiten in der MSDN-Online-Referenz besonders schnell zu
finden.
Ein weiterer großer Teil dieses Kapitels befasst sich mit XML und
der Transformationssprache XSLT. Damit wird eine profunde Ba-
sis f1r die in .NET weit verbreitete Nutzung von XML geliefert.
Die XML-Fhigkeit des SQL Servers 2000 f1hrt dar1ber hinaus zu
einer wichtigen Schnittstelle, die die Beherrschung von SQL und
XML gleichermaßen erfordert.
F1r den Einsatz mit ASP.NET kommt MSDE in der Praxis nicht in
Betracht. Sie k&nnen jedoch Ihre lokalen Anwendungen damit tes-
ten und dann im Praxisbetrieb auf SQL Server laufen lassen. Die
gr&ßte Einschrnkung stellt dabei die Anzahl der Verbindungen
dar, die ge&ffnet werden k&nnen. Diese sind bei MSDE auf zehn
beschrnkt.
ADO.NET suggeriert, dass die Abfrage von Datenbanken durch SQL trotz
geeignete Methoden und Eigenschaften erfolgen kann. Tatschlich ADO.NET?
geht es aber mehr darum, die Art und Weise des Zugriffs so ein-
fach wie m&glich zu gestalten und gleichzeitig die technischen
Ressourcen bestm&glich auszunutzen. Im Endeffekt basiert jedoch
Sandini Bib
348 5 Grundlagen der Datenspeicherung
E INSERT
Damit werden Daten eingef1gt.
E DELETE
Dieser Befehl l&scht Daten wieder.
E UPDATE
Vorhandene Daten werden damit aktualisiert.
E SELECT
Der sehr mchtige Befehl erlaubt die Abfrage von Daten.
Der folgende Abschnitt f0hrt sehr kompakt in die Grundlagen von SQL
t ein, ohne die Sie ADO.NET nicht dauerhaft erfolgreich einsetzen k$n-
nen. Das Kapitel zu ADO.NET zeigt dann dennoch, wieweit Sie ohne
SQL kommen k$nnen. In der Praxis wird oft mehr verlangt. Bl#ttern Sie
dann in dieses Kapitel hier und den Abschnitt 0ber Transact-SQL zu-
r0ck.
Was ist ADO.NET? Mit der Datenbank auf der einen Seite und einer Abfragesprache
gelangen die Daten noch nicht zum Benutzer. Zwischen ASP.NET
und der Datenbankschnittstelle stellt das .NET-Framework eine
Schicht zur Verf1gung, die den Zugriff weitgehend abstrahiert.
Diese Schicht wird ADO.NET genannt. Sie bildet sich aus einer
ganzen Reihe von Klassen im Namensraum System.Data. Weitere
Namensrume folgen darunter, was auf den Umfang der M&g-
lichkeiten hindeutet, denn jeder enthlt unzhlige Klassen. Vom
Prinzip her schafft ADO.NET eine lokale Kopie des aktuell gefrag-
ten Teils der Datenbank. Diese Kopie wird, wann immer es m&g-
lich ist, im Speicher gehalten. Entsprechend effizient k&nnen Ab-
fragen erfolgen.
Daten-Steuer- Nun steht dem programmatischen Zugriff von ASP.NET nichts
elemente mehr im Wege. Was noch fehlt, sind geeignete Web Server-Steuer-
elemente, die die Darstellung 1bernehmen. Auch hier kann der
Softwareentwickler aus dem Vollen sch&pfen. Nahezu jedes Ele-
ment einer ASP.NET-Seite kann eine Datenquelle an sich binden
und so die Darstellung sehr einfach und direkt 1bernehmen.
Die Datenquelle beschrnkt sich dabei nicht auf Objekte aus
Sandini Bib
SQL mit MS Access lernen 349
die als Basis eines Shops dienen kann. In weiteren Beispielen wird
die fertige Version dann eingesetzt, um die Bestellinformationen
aufzunehmen.
FIRMA, Varchar(80)
STRASSE, Varchar(80)
ORT, Varchar(50)
PLZ, Integer(5)
Char (feste Lnge zwischen 1 und 255 Zeichen) oder Varchar (varia-
ble Lnge bis 255 Zeichen) gespeichert, wobei in beiden Fllen die
maximale Zeichenanzahl festgelegt ist. Char in SQL und Char
VB.NET sind also sehr verschiedene Datentypen.
Bei den folgenden Seiten werden Sie sich vielleicht fragen, ob Sie die Da-
tenbankgrundlagen wirklich brauchen – nur um ein kleines Projekt zu
entwickeln. Die Antwort ist ein klares »Ja«: auch kleine Datenbanken
Sandini Bib
SQL mit MS Access lernen 353
sind, wenn ein falsches Modell zugrunde liegt, nicht wirklich beherrsch-
bar. Sie investieren ein Mehrfaches an Zeit, um einfachste Funktionen mit
einer Programmiersprache und dem Framework umst#ndlich nachzubil-
den oder k$nnen bestimmte Strukturen 0berhaupt nicht sinnvoll abbilden.
Das Verst#ndnis f0r diese kompakte Einf0hrung ist unbedingt notwendig.
Die Tabelle enthlt alle Informationen, die f1r die Abwicklung be-
n&tigt werden, sowohl die Namen als auch die Daten der Artikel
und die Bestellinformationen. Stellen Sie sich außerdem vor, dass
weitere nicht gezeigte Spalten f1r die Adresse und die Artikel-
beschreibung usw. in der Praxis hinzukommen. Diese Tabelle ist
offensichtlich sehr un1bersichtlich und – was noch schwerer
wiegt, – sie enthlt redundante Daten. So tauchen sowohl die Na-
men als auch Artikelnummern und Preise mehrfach auf. Die Pfle-
ge einer solchen Tabelle ist sehr aufwndig. Die :nderung an ei-
nem Datensatz – beispielsweise einem Benutzernamen – w1rde
dazu f1hren, dass mit der unmittelbaren Operation nicht im Zu-
sammenhang stehende :nderungen an anderen Datenstzen er-
forderlich sind.
Die oben gezeigte Tabelle 5.1 sollten Sie also in mindestens drei
Tabellen splitten. Die erste enthlt alle Adressinformationen. Die
gezeigte Auswahl ist nur ein Teil dieser Tabelle, damit hier die
Jbersicht nicht verloren geht:
Der Gesamtpreis wurde mit aufgenommen, weil der Preis der Ar- Stamm- und
tikeltabelle sich ndern kann, whrend der Preis einmal verkauf- Betriebsdaten
ter Artikel sich nicht mehr ndern darf. Beim Normalisieren muss
also immer beachtet werden, wo sich Daten ndern k&nnen und
welche Auswirkungen die Verkn1pfungen haben und ob dies
auch beabsichtigt ist. Man muss deshalb sorgfltig zwischen
»Stammdaten« und »Betriebsdaten« unterscheiden. Im Beispiel ist
der Preis in der Tabelle Produkte vom Typ Stammdaten. Alle Ope-
rationen, die Werte dieser Art 1bernehmen, entnehmen sie aus ei-
ner Stammdatentabelle. Die Bestelltabelle zeichnet dagegen einen
Momentanzustand auf. Dieser muss erhalten bleiben, auch wenn
sich Stammdaten ndern. Es ist Aufgabe der Programmlogik, zwi-
schen beiden Zustnden eine Beziehung herzustellen, wenn dies
erforderlich sein sollte.
Lassen Sie sich an dieser Stelle nicht davon abbringen, sich intensiv mit
Datenbanken auseinander zu setzen, auch wenn dies kompliziert er-
scheint. Es gibt einfache Anwendungsf#lle, die keine Normalisierung
ben$tigen und die nur aus einer einzigen Tabelle bestehen. Es ist aber
notwendig zu wissen, was auf Sie zukommt, wenn komplexere Zusam-
menh#nge datentechnisch abgebildet werden m0ssen. Es ist der An-
spruch dieses Buches, dieses Wissen zu vermitteln.
Sandini Bib
358 5 Grundlagen der Datenspeicherung
Freilich nutzen Sie danach auf dem Weg zum Profi nicht die As-
sistenten von Access daf1r, sondern SQL, um Daten einzuf1gen,
zu l&schen oder zu ndern. Denn exakt dieses Wissen wird da-
nach in der ASP.NET/ADO.NET-Programmierung eingesetzt,
um die Datenbank 1ber ein Programm zu bedienen.
F0r Eilige ist die Tabelle auf der CD zum Buch zu finden. Sie sollten
t aber die Gelegenheit nutzen, die Schritte selbst anhand der folgenden An-
leitung nachzuvollziehen.
Sandini Bib
SQL mit MS Access lernen 359
Schließen Sie nun den Assistenten. Starten Sie ihn erneut, um die
Tabelle Artikel zu erzeugen. Auch diese Tabelle wird f1r einige
der folgenden Jbungen ben&tigt.
Sandini Bib
360 5 Grundlagen der Datenspeicherung
Mit INSERT INTO f1gen Sie Daten hinzu. Der Befehl wird folgender-
maßen eingesetzt:
Sandini Bib
SQL mit MS Access lernen 363
Die Syntax des Befehls INSERT ist einfach. Zu beachten ist, dass die
Anzahl der Spalten mit den Werten 1bereinstimmen muss. Eben-
so ist die Reihenfolge entscheidend. Zeichenketten m1ssen in An-
f1hrungszeichen stehen. Es gibt auch eine verk1rzte Form, bei der
hinter VALUES exakt die Anzahl der definierten Spalten bedient
werden muss:
Die Spalte id wurde im Beispiel weggelassen, weil sie durch das Feld-
attribut AutoWert automatisch mit fortlaufenden Nummern gef0llt
wird.
Geben Sie nun noch einige weitere Datenstze ein, um ein wenig
mit den Daten spielen zu k&nnen. Es erscheint 1brigens vor jeder
Einf1geoperation ein Warnhinweis in Access, bei dem Sie die Ein-
gabe besttigen m1ssen. Beim Absenden von INSERT 1ber ein Pro-
gramm wird diese Barriere nicht mehr st&ren.
Mit einem Doppelklick auf den Namen der Tabelle k&nnen Sie se-
hen, ob der Vorgang erfolgreich war und alle Daten erfasst wur-
den. Wiederholen Sie die letzte Eingabe noch mit einem fehlerhaf-
ten Wert – in der folgenden Abbildung steckt der Fehler in Zeile
2. Die fehlerhafte Zeile wird im folgenden Abschnitt mit einem
neuen Kommando korrigiert.
Sandini Bib
364 5 Grundlagen der Datenspeicherung
Auch hier erscheint in Access wie schon bei INSERT und DELETE der
Warnhinweis. Ohne WHERE werden alle Datenstze gendert – was
meist fatale Folgen hat. Mehrere Spalten ndern Sie gleichzeitig, in
dem die entsprechenden Anweisungen der Form »Spalte = Neuer
Wert« als Liste, durch Kommata getrennt, aufgef1hrt werden:
UPDATE Adressen SET name = 'JQrg Krause', plz = '12683' WHERE id = 1
Die einfachste Abfrage ist die Ausgabe aller Datenstze einer Ta-
belle; mit dem folgenden Befehl werden alle Name aus der Tabelle
Adressen angezeigt:
Nun besteht die Kunst im Umgang mit SQL nicht darin, ganze Ta-
bellen abzurufen. Oft wird ein ganz bestimmter Datensatz ben&-
tigt oder es ist sogar ein Zusammenhang zwischen mehreren Ta-
bellen herzustellen. Letzterer Fall resultiert vor allem aus der
Normalisierung der Daten, die zur »Auftrennung« redundanter
Informationen f1hrt.
SELECT verstehen Das »*« in der letzten Abfrage ist eine Kurzform f1r »alle Felder«.
Der Aufbau des Kommandos orientiert sich ansonsten an folgen-
dem Muster:
Dabei ist mindestens eine Spalte und eine Tabelle anzugeben, wei-
tere Angaben sind optional. Der Befehl besteht aus zwei Schl1ssel-
worten. Das Schl1sselwort SELECT (dt. Auswahl) leitet den Befehl
ein, FROM (dt. aus) whlt die Tabelle und WHERE (dt. wo, wobei) ist
die Bedingung.
Abfragen gestalten
Sehen Sie sich den folgenden Zugriff auf die Tabelle Artikel an:
Sie k&nnen sich nun alle Preise mit und ohne Mehrwertsteuer an-
sehen:
ORDER BY ... F1r eine bestm&gliche Jbersicht k&nnen Sie die Ausgabe sortieren
DESC|ASC lassen:
Sortieren von Mit DESC (vom engl. descend) wird absteigend sortiert und mit ASC
Daten (vom engl. ascend) k&nnen Sie auch aufsteigend sortieren. Sortiert
wird nach dem ersten oder dem angegebenen Feld, hier also nach
preis. Zwei Dinge sollten Sie beachten: Das Sortieren großer Daten-
banken beansprucht den Server stark. Sie k&nnen außerdem nur
nach den Spalten sortieren, die auch ausgegeben werden. Norma-
lerweise k&nnen Sie aber davon ausgehen, dass die Sortierung in
der Datenbank schneller ist, als mit VB.NET und dem Framework.
Voraussetzung ist jedoch eine entsprechende Indizierung der Da-
tenbank.
Die Verwendung des Index passiert intern, sodass Sie sich bei
der Gestaltung der SELECT-Kommandos darauf nicht mehr
konzentrieren m1ssen. Indizes wirken 1brigens auch positiv
auf die Geschwindigkeit beim Einf1gen mit INSERT, wenn be-
reits sehr viele Daten vorhanden sind.
SELECT * FROM Artikel WHERE preis > 100 AND preis < 200
Die Schreibweise mit BETWEEN (dt. zwischen) ist zur vorher genutz-
ten Form quivalent; das Ergebnis ist identisch, wenn Sie beach-
ten, dass BETWEEN auf Gleichheit der Grenzwerte pr1ft. Dies ent-
sprche <= bzw. >= im vorhergehenden Beispiel.
SQL-Funktionen Als Nchstes sollen Artikel anhand des Namens ausgewhlt wer-
den. Die einfache Abfrage lautet:
SELECT nummer, name É
FROM Artikel É
WHERE LCASE (name) LIKE '*pro*'
Alle Reihen sollen ermittelt werden, die in der Spalte plz die Zei- IN
chenkette »12683« oder »89487« haben. Dies erledigt zuverlssig
der Operator IN:
Das ist sicher nicht das erwartete Ergebnis, denn Access hat hier
einfach alle Tabellen miteinander vermischt. Die Beziehungen, die
anfangs ja nur gedanklich existierten, sind nicht angegeben wor-
den. Sie k&nnen nicht davon ausgehen, dass nur die Benennung
mit »id« zu brauchbaren Ergebnissen f1hrt. Letztlich steht Ihnen
die Namenswahl sowieso frei. Also m1ssen die Beziehungen an-
gegeben werden. Dazu dient wiederum die WHERE-Bedingung:
Aliase Neben der Angabe hinter WHERE wurden hier auch noch so genann-
te Alias-Namen verwendet (a f1r Adressen, p f1r Artikel und b f1r
Bestellungen). Diese dienen nur der Verk1rzung der Schreibwei-
se. Schauen Sie sich zum Vergleich mit dem letzten Ergebnis die
verwendete Tabelle Bestellungen an. Das Ergebnis der Abfrage
spiegelt diese Tabelle wieder, allerdings sind neben den Bestell-
IDs auch die Namen der Kufer und Artikel zu finden:
Abbildung 5.13: Korrekte Abfrage der Bestellungen mit Zuordnungen aus anderen
Tabellen
INNER JOIN Letztlich basiert das ganze Verfahren nur auf der Verbindung der
ID-Spalten: a.id = b.[k-id] usw. Die Verkn1pfung von zwei Tabel-
len kann in SQL auch mit dem Operator INNER JOIN ausgedr1ckt
werden. Das Ergebnis erscheint immer dann, wenn zwei Felder
der beiden Tabellen 1bereinstimmen:
Zusammenfassung
Gezeigt wurde ein Jberblick 1ber den grundstzlichen Aufbau ei-
ner Datenbank, die Arbeitsweise eines Datenbankmanagement-
systems und Sie haben die elementarsten SQL-Befehle kennen ge-
lernt. Damit lassen sich bereits kleinere datenbankgest1tzte
Webprojekte umsetzen. F1r den Zugriff auf die Datenbank aus
Sandini Bib
Der Datenbankzugriff in Visual Studio .NET 373
Der Zugriff auf den SQL Server 2000 zum Anlegen von neuen Daten-
banken ist nur mit der Enterprise Version von Visual Studio .NET m$g-
lich. Mit der Professional Version k$nnen Sie lediglich Datenbanken in
der SQL Server Desktop Edition (MSDE) erstellen, die f0r Webanwen-
dungen kaum zum Einsatz kommen d0rfte. Die Manipulation von Da-
ten in vorhandenen Strukturen ist dagegen auch mit VS.NET Professio-
nal m$glich, was in den meisten F#llen ausreichend ist.
Wenn Sie den Datenbankserver im lokalen Netzwerk oder auf Ihrem Ent-
wicklungssystem betreiben, ist der direkte Zugriff unkritisch. Steht der
Server dagegen beim Provider, wird er mit Sicherheit hinter einer Fire-
wall platziert sein. Dann k$nnen Sie mit VS.NET ohnehin nicht direkt
zugreifen, sondern nur 0ber eine Web-Schnittstelle. Informieren Sie sich
bei Ihrem Provider, wie er diese Schnittstelle realisiert hat.
Zur Vorbereitung der Jbungen sollten Sie sich mit der Struktur
der kleinen Spiel-Datenbank Shop vertraut machen. Der Dia-
gramm-Designer des SQL Servers zeigt diese folgendermaßen:
Sandini Bib
376 5 Grundlagen der Datenspeicherung
E VARCHAR(l5nge)
Zeichenkette mit minimal 0 und maximal l5nge Zeichen. Die
Lnge kann h&chstens 8.000 Zeichen betragen.
E CHAR(l5nge)
Zeichenkette mit genau l5nge Zeichen. Maximal 8.000 Zeichen
sind m&glich.
E NVCHAR(l5nge)
Unicode-Zeichenkettenfeld mit variabler Lnge. Das Feld kann
maximal 4.000 Unicode-Zeichen in 8.000 Bytes speichern.
E NCHAR(l5nge)
Unicode-Zeichenkette mit fester Lnge. Das Feld kann maxi-
mal 4.000 Unicode-Zeichen in 8.000 Bytes speichern.
Bin#rdaten speichern
Binre Felder k&nnen bis zu 8.000 Byte aufnehmen. Wenn immer Bin re Felder
es der Platzverbrauch erlaubt, sollten Sie BINARY verwenden. Diese
Form ist schneller, da der SQL-Server intern mit Speicherseiten
fester Gr&ße arbeitet und deshalb mit Feldern konstanter Gr&ße
besser umgehen kann. Sie werden wie folgt definiert:
E BINARY(byte)
Binrfeld fester Lnge, beginnend mit 1. Der tatschliche Spei-
cherplatz betrgt n+4 Byte. Der physische Platzverbrauch ist
unabhngig vom Inhalt und abhngig von der Definition.
E VARBINARY(byte)
Dieses Feld hat keine feste Lnge, sondern passt sich dem In-
halt an und verbraucht nur so viel Platz, wie der Inhalt in An-
spruch nimmt.
E TEXT
Dieser Datentyp dient der Speicherung von Textfeldern bis zu
einer Gr&ße von 2 GByte.
Sandini Bib
378 5 Grundlagen der Datenspeicherung
E NTEXT
Dieser Datentyp speichert 1.073.741.823 Unicode-Zeichen. Da
Unicode-Zeichen 16 Bit breit sind, entspricht dies 1 Milliarde
Zeichen oder 2 GByte.
E IMAGE
Dieser Datentyp speichert 2 GByte (2.147.483.647 Byte) binrer
Daten. Wenn die Daten mit INSERT direkt eingef1gt werden
(siehe auch WRITETXT), muss vor der Zeichenkette das Symbol
»0x« stehen und der Rest eine hexadezimale Zeichenfolge der
Binrdaten ergeben.
Numerische Datentypen
Ganzzahlen Umfangreicher sind die numerischen Datentypen. Zuerst die
Ganzzahltypen:
E BIGINT
63
Der Wertebereich dieses Datentyps reicht von -2
63
(-922.337.203.685.477,5808) bis +2 (+922.337.203.685.477,5807,
ca. 922 Billionen).
E INT
31 31
Wertebereich -2 (-2.147.483.646) bis +2 (+2.147.483.647), nur
ganzzahlige Werte (32 Bit Integer).
E SMALLINT
Wertebereich -32.767 bis +32.768, nur ganzzahlige Werte
(16 Bit Integer).
E TINYINT
Wertebereich von 0 bis 255 (1 Byte). Negative Werte werden
nicht unterst1tzt.
E NUMERIC(int, frac)
38 38
Gleitkommazahlen von -10 +1 bis 10 -1. Der Parameter int
gibt die Anzahl der Stellen vor dem Komma an, frac die An-
zahl der Dezimalstellen.
Sandini Bib
Transact-SQL – SQL mit dem SQL Server 2000 lernen 379
E DECIMAL
Dieser Typ entspricht exakt NUMERIC und existiert aus Gr1nden
der Kompatibilitt mit dem ANSI SQL-92-Standard.
E FLOAT(n)
-308 308
Gleitkommazahlen von 2,23 x 10 bis 1,79 x 10 . Der Para-
meter n gibt die Genauigkeit an.
E DOUBLE PRECISION
Dieser Typ entspricht exakt FLOAT und existiert aus Gr1nden
der Kompatibilitt mit dem ANSI SQL-92-Standard.
Bei der Arbeit mit Geldwerten k&nnen die Whrungstypen inte- Monet re Werte
ressant sein. Diese Datentypen verwenden immer vier Kom-
mastellen, werden bei der Ausgabe auf 1 Hundertstel (Pfennig,
Cent) gerundet und rechnen intern mit einem Zehntausendstel
des Basiswertes. Es sind aber reine numerische Werte, die keine
Whrungsformatierungen mitf1hren (wie beispielsweise E oder
$). Hier die beiden m&glichen Typen:
E MONEY
Planen Sie große Geschfte, speichern Sie damit Ihre Kon-
tostnde. Der Wertebereich dieses Datentyps reicht von
-922.337.203.685.477,5808 bis +922.337.203.685.477,5807 (922
Billionen).
E SMALLMONEY
Knapp f1r den Heimgebrauch reicht der Wertebereich dieses
Datentyps von -214.748,3648 bis +214.748,3648.
Bin#rwerte
Auch logische oder besser Boolesche Werte lassen sich speichern. Bitfelder
Der SQL Server 2000 legt einfach ein Bitfeld an, das 1 Bit enthlt. 0
ist FALSE (falsch), 1 ist gleich TRUE (wahr). Das Schl1sselwort daf1r
ist BIT. Intern werden Bit-Felder in Bytes konvertiert, 1 Bit nimmt
mindestens 1 Byte in Anspruch, mehrere Bitfelder werden aber in
einem Byte gesammelt.
Sandini Bib
380 5 Grundlagen der Datenspeicherung
E DATETIME
Daten ab dem 1.1.1753 bis zum 31.12.9999 und darin Zeiten in
Schritten zu einer Millisekunde lassen sich speichern. Das
klingt besser als es tatschlich ist. Falls Sie die Geschichte des
Christentums in einer SQL-Datenbank erfassen wollen, wer-
den Sie schnell bemerken, dass Computer nicht bibelfest sind.
Immerhin ist der Datentyp Jahr-2000-sicher. Vor allem aber
sind die in .NET verf1gbaren Kalender f1r gr&ßere Datums-
bereiche ausgelegt (meist ab dem Jahr 1). Jberlegen Sie des-
halb sorgfltig, ob DATETIME f1r Ihre Zwecke ausreichend ist.
E SMALLDATETIME
Dieser Typ speichert vom 1.1.1900 bis 6.6.2079.
CURSOR Der SQL Server kann Zugriffe auf mehrere Datenstze 1ber Zeiger
steuern. Diese Technik werden Sie m&glicherweise verwenden
m1ssen, weil die mit ADO.NET eingef1hrte zeigerlose Methode
nicht immer optimal ist, auch wenn dieser Mangel durch eine
Vielzahl sehr fortschrittlicher Funktionen weitgehend ausgegli-
chen wird. Wollen Sie Zeiger speichern, verwenden Sie den Da-
tentyp CURSOR.
Sandini Bib
Transact-SQL – SQL mit dem SQL Server 2000 lernen 381
Wenn Sie einer Spalte einen bestimmten Datentyp nicht zuweisen SQL_VARIANT
k&nnen, verwenden Sie SQL_VARIANT. Dies sollte die ganz große
Ausnahme sein. Es ist wichtig, Wertebereiche immer so eng wie
m&glich zu deklarieren. SQL_VARIANT findet gelegentlich in tempo-
rren Tabellen Verwendung.
Der Datentyp TABLE speichert Ergebnisse von Abfragen, die f1r TABLE
sich genommen wieder Tabellen darstellen. Er spart m&glicher-
weise das Erzeugen einer temporren Tabelle.
Benutzerdefinierte Datentypen
Wenn Sie bestimmte parameterisierte Datentypen hufig ben&ti- Systemproze-
gen, ist es sinnvoll, diese als benutzerdefinierte zu speichern. Die duren zum
Anlegen benutzer-
Erstellung erfolgt mit einer gespeicherten Systemprozedur, definierter Daten-
sp_addtype. Drei Angaben sind notwendig: typen
Dateistruktur und Jede einzelnen Angabe ist dabei optional. Die Zahlenangaben ent-
-gr<ße sprechen Megabyte. Sie k&nnen mehrere Dateien angeben. Die
Datenbank wird dann auf mehrere physische Dateien verteilt. Es
ist nicht unbedingt notwendig, die Dateigr&ße anzugegeben. Der
SQL Server 2000 erh&ht die Gr&ße der Datei nach Bedarf. Dabei
wird die Gr&ße immer bei Erreichen der Grenzwerte um 10 % er-
h&ht. Wenn Sie eine andere Strategie der Vergr&ßerung w1n-
schen, setzen Sie den Parameter FILEGROWN ein.
Wenn Sie mehrere Dateien angeben und diese auf Festplatten ablegen,
t die durch getrennte Adapter bedient werden, erh$hen Sie deutlich die Ge-
schwindigkeit der Datenverteilung.
Systemdatenbank Die neue Datenbank ist nicht leer. Sie enthlt alle Objekte, die in
model der Systemdatenbank model untergebracht sind. Wenn Sie in jeder
neuen Datenbank immer wieder bestimmte Objekte ben&tigen,
beispielsweise nutzerdefinierte Datentypen, dann definieren Sie
diese in der Datenbank model.
Sandini Bib
Transact-SQL – SQL mit dem SQL Server 2000 lernen 383
Wenn Sie eine Datenbank nicht mehr ben&tigen, k&nnen Sie diese
folgendermaßen entfernen:
Datenbankdefinition #ndern
Sie k&nnen die Eigenschaften bestehender Datenbanken leicht n- ALTER DATABASE
dern. Dazu wird der Befehl ALTER DATABASE verwendet. Die Parame-
ter entsprechen dem bereits besprochenen Befehl CREATE DATABASE.
Neben der :nderung der Dateigr&ße k&nnen Sie vor allem wei-
tere Dateien hinzuf1gen oder l&schen. Die letzte verbleibende Da-
tei muss groß genug sein, um alle Objekte der Datenbank aufneh-
men zu k&nnen. Das folgende Beispiel entfernt eine Datei aus der
Datenbank:
Das nchste Beispiel zeigt, wie die Gr&ße auf »unbegrenzt« ge-
setzt werden kann:
USE database
CREATE TABLE Eine Tabelle Bestellungen k&nnen Sie leicht folgendermaßen anle-
gen:
Sie haben jetzt einige neue Tabellen. Der Vorgang ist jedoch erkl-
rungsbed1rftig, denn der Teufel steckt im Detail. Hinter jedem
Spaltennamen steht der Datentypbezeichner. Diesen sollten Sie ge-
nau kennen. Mehr Informationen dazu finden Sie in Abschnitt 5.5.1,
»Datentypen in T-SQL« ab Seite 376. Jber diese Datentypen hinaus
sind jedoch weitere Einschrnkungen und Definitionen m&glich.
Bei der Schreibweise der Spaltennamen ist zu beachten, dass Minus- und
Leerzeichen nur toleriert werden, wenn der Name in eckigen Klammern
steht. Wenn Sie Tabellen mit den Visual Tools des SQL Servers entwer-
t
fen und dann SQL-Skripte generieren, stehen alle Namen in eckigen
Klammern. Dies ist der sicherste Weg.
E PRIMARY KEY
Erklrt diese Spalte zum Primrschl1ssel. Nur eine Spalte ei-
ner Tabelle darf einen Primrschl1ssel haben. Jeder Datensatz
der Spalte muss eindeutig sein und dient der Referenzierung
Sandini Bib
386 5 Grundlagen der Datenspeicherung
Achten Sie auf den Datentyp. Er muss einen ausreichenden Datentyp f=r
Wertebereich f1r alle Datenstze haben; TINYINT wre hierf1r IDENTITY-Spalten
kaum geeignet. Die Parameter hinter IDENTITY sind optional,
ohne Angabe wird (1,1) angenommen. Der erste Wert ist der
Startwert und der zweite die Schrittweite.
IDENTITY ist nur innerhalb einer Tabelle eindeutig. F1r globale,
die gesamte Datenbank betreffende Eindeutigkeit nutzen Sie
besser UNIQUEIDENTIFIER oder ROWGUIDCOL. Wenn Sie ein eindeuti-
ges Feld 1ber die gesamte Datenbank ben&tigen, nutzen Sie
den Datentype UNIQUEIDENTIFIER und setzen den Startwert mit
der Funktion NEWID():
CREATE TABLE firmen
( key UNIQUEIDENTIFIER IDENTITY(NEWID())
)
E DEFAULT
Damit bei neuen Feldern nichts schiefgeht, k&nnen Sie auch
gleich einen Standardwert zuweisen. Wird kein Inhalt gelie-
fert, trgt sich die Tabelle eben selbst einen Wert ein:
CREATE TABLE artikel
( artikel VARCHAR(60),
text TEXT,
preis NUM,
bestelldatum DATETIME DEFAULT '01.01.1998')
E ROWGUIDCOL
Mit dieser Eigenschaft erzwingen Sie eine global eindeutige
Spalte. Nur eine Spalte einer Tabelle darf diese Eigenschaft ha-
ben. Der Begriff »global« ist w&rtlich zu nehmen, es wird ga-
rantiert, dass dieser Wert auch bei keiner anderen Installation
des SQL Servers verwendet wird.
Tabellen leeren Wollen Sie nur smtliche Datenstze l&schen, verwenden Sie die-
mit TRUNCATE sen Befehl:
TABLE
TRUNCATE TABLE temporaer
Sie k&nnen mit ALTER keine neue Tabelle erzeugen, wenigstens ei-
ne Spalte muss bereits vorhanden sein.
5.5.3 Indizes
Tabellen werden oft und intensiv abgefragt. Auf die problemati-
sche Belastung des Servers wurde bereits hingewiesen. Eine M&g-
lichkeit, effizienter zu arbeiten, sind Indizes. :hnlich einem Buch,
in dem der Index schnelleres Suchen erm&glicht, kann ein Feld ei-
ner Tabelle zum Indexfeld erklrt werden.
Abbildung 5.17: Vereinfachte Darstellung der Suchstrategie mit nicht gruppiertem Index
Jeder Index muss nat1rlich eine Spalte als Basis nutzen k&nnen.
SQL kann sogar mehrere Spalten als Index heranziehen. So k&n-
nen Sie eine Tabelle mit Vor- und Zunamen erzeugen. Wenn Sie
oft nach dem vollstndigen Namen suchen, sollten Sie einen Index
erstellen, der sich auf beide Felder bezieht. Es gibt außerdem die
M&glichkeit, einen Index als eindeutig (engl. unique) zu bezeich-
nen. Damit verhindern Sie, dass Eintrge doppelt vorkommen.
Sandini Bib
390 5 Grundlagen der Datenspeicherung
Sie k&nnen auch innerhalb des Befehls CREATE TABLE den Parameter
INDEX verwenden. Manchmal macht die Erzeugung eines Index aber
erst zu einem spteren Zeitpunkt Sinn. Befinden sich viele Daten in
der Tabelle, kann der Vorgang einige Zeit in Anspruch nehmen.
DROP INDEXDROP Sie k&nnen den Index auch wieder l&schen. Da der Index selbst eine
INDEX – wenn auch abhngige – Tabelle ist, eignet sich der Befehl DROP:
DROP INDEX [IX_Adressen].[name]
Wenn Sie einer Spalte einen Prim#rschl0ssel mit PRIMARY KEY zuweisen,
wird dies automatisch zu einem gruppierten Index auf Basis dieser Spal-
te f0hren.
Auch das Erzeugen eines Index mit zwei Spalten ist sehr einfach,
hier verbietet sich nat1rlich der Modifizierer CLUSTERED:
Mathematische Funktionen
Die folgende Tabelle zeigt die mathematischen Funktionen, die
Sie einsetzen k&nnen:
Funktion Beschreibung
ABS(n) Absoluter Betrag
ACOS(f) Arcuskosinus
ASIN(f) Arcussinus
ATAN(f) Arcustangens
ATN2(f1, f2) Arcustangens (Winkel) zwischen f1 und f2
CEILING(n) Die kleinste Ganzzahl gr3ßer oder gleich dem
angegebenen numerischen Ausdruck.
COS(f) Kosinus
COT(f) Kotangens
DEGREES(n) Umrechnung Radiant in Grad
EXP(f) Potenz zur Basis e
FLOOR(n) Die gr3ßte Ganzzahl kleiner oder gleich dem
angegebenen numerischen Ausdruck.
LOG(f) Natrlicher Logarithmus
LOG10(f) Dekadischer Logarithmus
PI() Konstante Pi
POWER(n, p) Zahl n zur Potenz p
RADIANS(f) Umrechnung in Radiant
RAND(f) Zufallszahl
ROUND(n, l[,e]) Rundet Werte n mathematisch auf l Stellen.
Wenn e 0 ist, wird gerundet, andernfalls gekrzt
SIGN(n) Vorzeichen (gibt -1, 0 oder 1 zurck)
SIN(f) Sinus
SQUARE(f) Quadrat
SQRT(f) Quadratwurzel
TAN(f) Tangens
Aggregat-Funktionen
Mit f1nf einfachen Rechenoperationen kann auch spaltenweise
gearbeitet werden. Die Auswahl beginnt wieder mit dem Befehl
SELECT, dem eine Funktion nachgestellt wird. Die Anwendung ist
nur mit numerischen Feldern sinnvoll.
Systemfunktionen
Die Systemfunktionen liefern Angaben 1ber Objekte und interne
Zustnde des SQL-Servers.
Sicherheitsfunktionen
Die folgenden Funktionen dienen der Kontrolle und Steuerung der
Sicherheit des Datenbankservers oder der Datenbankanwendung:
Sandini Bib
Transact-SQL – SQL mit dem SQL Server 2000 lernen 395
Gruppierungen
Bei der Anwendung von Summenfunktionen werden Sie oft fest- GROUP BY
stellen, dass Zwischensummen ben&tigt werden. SQL bietet daf1r
einige Ergnzungen des SELECT-Befehls. Wenn Sie sich beispiels-
weise die Artikel und die dazu passende Umstze mit folgendem
Befehl ansehen, erhalten Sie eine wenig hilfreiche Liste:
Hier wird die Ausgabe der Namen auf einen bestimmten Namen COUNT(*)
(nmlich auf den ersten, nach dem Alphabet) eingeschrnkt. An-
dersherum k&nnen Sie auch die Gruppierung auf mehrere Spalten
ausdehnen. Stimmen alle Spalten mit allen Gruppen 1berein, ist
die Ausgabe wieder ungruppiert. Hier die andere Variante:
Die Funktion COUNT(*) bezieht sich bei Gruppen immer auf die An-
zahl der Datenstze in der Gruppe. Die Ausgabe von 1 in der
rechten Spalte im letzten Beispiel kann sinnvoll sein, wenn Sie die
Anzahl pro Gruppe ben&tigen, nicht jedoch, wenn Sie parallel die
Gesamtzahl der Datenstze ermitteln wollten.
Um mit Gruppen flexibel umgehen zu k&nnen, kann auch die Bil- HAVING
dung von Gruppen Einschrnkungen unterworfen werden. :hn-
lich der WHERE-Bedingung k&nnen Sie hinter dem Schl1sselwort
GROUP BY weitere Bedingungen folgen lassen, die durch HAVING ein-
geleitet werden. Die Bedingung wird gegen das Gruppenergebnis
getestet:
Hier werden nur die Artikel angezeigt, die mehr als zwei Bestel-
lungen haben. Zugleich werden die Umsatzsummen ausgegeben.
Damit das funktioniert, m1ssen Sie nat1rlich genug Bestelldaten-
stze erfasst haben.
Abbildung 5.18: GROUP BY erzwingt eine Sortierung, die allein 25% der Leistung benCtigt,
die dieser Befehl verbraucht (siehe zweites Symbol von rechts).
Wenn Sie also zuerst selektieren (mit WHERE) und dann gruppieren
(mit GROUP BY), steigern Sie die Leistung des Gesamtsystems. Der
Flexibilitt der WHERE-Bedingung kommt nicht zuletzt deshalb gro-
ße Bedeutung zu. Der folgende Abschnitt zeigt, was Sie mit WHERE
noch machen k&nnen.
WITH CUBE Oft werden Daten zu Berichten umgeformt und ausgegeben. F1r
WITH ROLLUP gelegentliche Auswertung und die Nutzung 1ber das Web sind
die Operatoren CUBE und ROLLUP bestens geeignet.
Rollt man die Liste der Ausgabewerte weiter nach unten, fllt auf,
dass auch alle gegenstzlichen Kombinationen, mit NULL in der
Spalte a-id, ausgegeben werden. Dies lsst sich mit WITH ROLLUP ver-
meiden:
GROUPING Im Zusammenhang mit CUBE trifft man auch auf GROUPING. Denn
die Unterscheidung der berechneten Spalten erfolgt anhand von
NULL-Werten. Wie aber kann man nun Reihen identifizieren, die
auf realen und nicht auf berechneten NULL-Werten basieren?
1 Das ist hier im Beispiel nicht der Fall, wenn Sie die Daten nicht von Hand
ndern. In der Praxis wre es denkbar, bereits den Warenkorb in der Bestel-
lungen-Tabelle abzulegen und die Summe erst dann einzutragen, wenn der
Kauf abgeschlossen wurde und eventuelle Rabatte ber1cksichtigt sind.
Sandini Bib
Transact-SQL – SQL mit dem SQL Server 2000 lernen 401
Im Ergebnis ist dann eine zustzliche Spalte zu sehen, die bei den
echten Zwischensummen eine »1« enthlt.
Ein weiterer Operator f1r die Erstellung von Berichten ist TOP. TOP TOP
liefert eine Anzahl von Reihen aus einer gr&ßeren Auswahl zu-
r1ck. So bietet der folgende Befehl nur die ersten sechs Datenstze
an:
Eine Alternative dazu bietet die Voreinstellung f1r die Anzahl der SET ROWCOUNT
Datenstze, SET ROWCOUNT:
SET ROWCOUNT 3
SELECT name FROM Bestellungen
SET ROWCOUNT 0
Sandini Bib
402 5 Grundlagen der Datenspeicherung
Mit dem letzten Befehl SET ROWCOUNT 0 wird die Ausgabe wieder f1r
alle Datenstze freigegeben. Der Befehl setzt eine globale Variable,
sodass die Beschrnkung sich f1r alle nachfolgenden Ausgaben
auswirkt. TOP wirkt dagegen nur innerhalb des aktuellen Befehls.
Wenn Sie keine kompatible Software schreiben, sollten Sie TOP be-
vorzugen.
Das folgende Beispiel zeigt neben der gruppierten Artikel die Ge-
samtsumme an:
Bei der Ausgabe werden Sie feststellen, dass die 1bliche Anord-
nung in einer Tabelle nicht mehr erfolgt.
Sandini Bib
404 5 Grundlagen der Datenspeicherung
Typumwandlungen
Wann immer es geht, wird der SQL Server 2000 Datentypen still-
schweigend umwandeln und Sie nicht mit Fehlermeldungen trak-
tieren. Sie k&nnen die korrekte Umsetzung aber gut unterst1tzen,
wenn Sie zwei Befehle kennen, die zur Umwandlung herangezo-
gen werden: CONVERT und CAST.
CONVERT Sie k&nnen die Datentypen eines Feldes nicht global ndern. Sie
k&nnen aber mit SELECT die Umwandlung Feld f1r Feld vorneh-
men – auch und letztendlich f1r alle Felder.
Der Befehl CONVERT wandelt das betreffende Feld vom Typ MONEY in
den Typ CHAR um. Die Lnge, die CHAR nutzen soll, betrgt zw&lf
Zeichen. Der Platz muss ausreichen, um den Preis und das Wort
»Euro« aufzunehmen, das bei dieser Gelegenheit gleich ange-
hngt wurde. Außerdem wurde der Preis mit 1,16 multipliziert –
aus dem Netto- wurde also ein Bruttopreis.
Das Problem ist nicht der etwas »wilde« Einbau der Zeichenkette.
Das ist durchaus erlaubt. Das Problem ist, dass das Feld price
(Typ MONEY) nicht automatisch gewandelt wird. Es funktioniert fol-
gendermaßen:
SELECT "Der aktuelle Preis ist: "+CONVERT(CHAR, preis) FROM Artikel
CAST entspricht in der Funktionsweise dem Befehl CONVERT. Mit CAST CAST
wird lediglich die ANSI-Kompatibilit,t gesichert. Wenn Sie in ab-
sehbarer Zeit eine Chance erkennen, einen anderen SQL-Server
als den MS SQL Server 2000 zu verwenden, sollten Sie besser CAST
verwenden. Die Anwendung ist ebenso einfach wie CONVERT:
Zeichenketten-Funktionen
Die folgende 5bersicht zeigt alle Zeichenketten-Funktionen. Die
wichtigsten werden danach besprochen, eine exakte Auflistung
finden Sie auch in der Referenz. Denken Sie beim Einsatz daran,
dass die Abwicklung im SQL-Server unter Umst,nden schneller
und effektiver ist, als durch eine Skriptsprache.
An dem Namen »Meier« sehen Sie eine h,ufige Schwierigkeit bei DIFFERENCE
Datenbankabfragen – es gibt verschiedene Scheibweisen mit glei- SOUNDEX
Mit SOUNDEX geben Sie den Schl:sselwert aus, der zur Beurteilung
verwendet wird. Das Schl:sselwort hat vier Stellen. Mit dem Ver-
gleich DIFFERENCE > Wert oder DIFFERENCE < Wert wird die zul,ssige
Abweichung festgelegt.
Zuerst wird der erste Buchstabe beider Zeichenketten als Basis SOUNDEX intern
verwendet. Stimmt der :berein, steht das erste Zeichen fest. Dann
geht es mit den n,chsten Konsonanten weiter. Vokale werden
ignoriert (das Y z,hlt als Vokal!), es sei denn, der Vokal steht an
erster Stelle, wie bei Yahoo.
Sandini Bib
408 5 Grundlagen der Datenspeicherung
Statt »mm« k@nnen Sie einen der Codes in der folgenden Tabelle
verwenden:
Erg,nzend sei noch die Funktion DATENAME erw,hnt, die genauso DATENAME
wie die Funktion DATEPART eingesetzt wird. Allerdings werden Zei-
chenketten statt Zahlen zur:ckgegeben. F:r die Codes »mm« und
Sandini Bib
410 5 Grundlagen der Datenspeicherung
Die Ausgabe der beiden Ergebnisse stellt den Namen des Wo-
chentags des aktuellen Datums dar.
DATEDIFF Berechnungen mit Daten k@nnen recht aufwendig sein. Auch hier
DATEADD hilft SQL weiter und stellt zwei weitere Funktionen zur Ver-
f:gung: DATEDIFF und DATEADD. Damit werden Differenzen berech-
net bzw. ein Zieldatum ermittelt. Die Tabelle Bestellungen enth,lt
die Bestelltermine der Artikel in bestelldatum. Sie k@nnen einfach
die Tage ermittelt, die die Bestellung eines Artikels zur:ck liegt:
SELECT [a-id], É
'Ist ' + CONVERT(VARCHAR(3), É
DATEDIFF(dd, bestelldatum,GETDATE())) É
+ ' Tage seit der letzten Bestellung' É
AS Zeitraum É
FROM Bestellungen
Sandini Bib
Transact-SQL – SQL mit dem SQL Server 2000 lernen 411
E INSENSITIVE
Wenn eine Deklaration mit diesem Parameter erfolgt, werden
die Daten in einer tempor,ren Tabelle tempdb abgelegt. <nde-
rungen an den Basistabellen wirken sich nicht auf das Abfra-
geergebnis aus. Der Zeiger ist außerdem nicht ,nderbar, das
heißt, die Daten k@nnen nur gelesen werden.
Sandini Bib
Transact-SQL – SQL mit dem SQL Server 2000 lernen 413
E SCROLL
Wenn angegeben, sind alle Bewegungsoperatoren (siehe FETCH)
erlaubt, ohne Angabe nur NEXT (nur Vorw,rtsbewegung).
E READ_ONLY
Verhindert, dass <nderungen an der Liste vorgenommen wer-
den k@nnen.
E UPDATE [OF spalten]
Zeigt die Spalten an, die ge,ndert werden d:rfen.
E LOCAL
Sagt, dass der Zeiger nur lokal in der Prozedur oder dem Trig-
ger gilt, wo er definiert wurde.
E GLOBAL
Dieser Zeiger ist immer verf:gbar.
E FORWARD ONLY
Der Zeiger kann nicht r:ckw,rts bewegt werden.
E STATIC
<nderungen an den Basistabellen, die urspr:nglich die Ergeb-
nisliste erzeugten, werden nicht weitergegeben und ,ndern
die Liste nicht.
E KEYSET
Wenn der Zeiger ge@ffnet wurde, werden <nderungen von
Schl:sselwerten nicht mehr ber:cksichtigt. Andere <nderun-
gen werden aber weitergereicht. Mit INSERT eingef:gte Reihen
werden nicht angezeigt.
E DYNAMIC
Alle <nderungen werden sofort angezeigt.
E SCROLL_LOCKS
Alle Datens,tze (Reihen), die sich in der Ergebnisliste befin-
den, werden in der Originaltabelle gesperrt, bis der Zugriff be-
endet wird. <nderungen und das L@schen von Datens,tzen
werden immer ausgef:hrt.
E OPTIMISTIC
Die Datens,tze werden nicht gesperrt, <nderungen an Daten-
s,tzen, die zwischenzeitlich gel@scht wurden, gehen verloren.
Sandini Bib
414 5 Grundlagen der Datenspeicherung
Mit dem Befehl FETCH steuern Sie den Zeiger. Hinter FETCH kann ei-
ne der folgenden Anweisungen stehen:
E NEXT
Setzt den Zeiger auf den n,chsten Eintrag.
E PRIOR
Setzt den Zeiger einen Eintrag zur:ck.
E FIRST
Setzt den Zeiger auf den ersten Eintrag.
E LAST
Setzt den Zeiger auf den letzten Eintrag.
E ABSOLUTE
Setzt den Zeiger auf einen bestimmten Eintrag.
E RELATIVE
Bewegt den Zeiger relativ zur aktuellen Position.
CLOSE CLOSE schließt den Zugriff auf den Zeiger, DEALLOCATE zerst@rt den
DEALLOCATE Zeiger endg:ltig.
SELECT * É
FROM bestellungen É
WHERE [a--id] = 1 OR [a--id] = 3 [a--id] = 4
Sandini Bib
416 5 Grundlagen der Datenspeicherung
Sie k@nnen nun beide Befehle kombinieren, sodass nur die Bestel-
lungen ausgegeben werden, bei denen Artikel bestellt wurden,
die einen Preis unter 200 E haben:
(SELECT [a--id] É
FROM artikel É
WHERE preis < 200)
Zuerst erstellt diese Abfrage eine Liste von Artikeln, deren Preis
kleiner als 200 E ist. SQL speichert diese Liste und f:hrt dann den
umgebenden SELECT-Befehl f:r jeden Datensatz der Liste aus. Dies
ist auch die Ursache f:r die Wahl des IN-Schl:sselwortes. Das um-
gebende Kommando k@nnte auch so aussehen:
SELECT * É
FROM bestellungen É
WHERE [a--id] IN (1, 3, 4)
Dieser Befehl zeigt alle teueren und – trotzdem – bestellten Titel an.
ANY ANY liefert also einzeln die Datens,tze zu einem einfachen Ver-
gleich zur:ck. Als Alternative zu NOT IN k@nnte die folgende Kons-
truktion dienen:
ALL Hier kommt als Auswahlkriterium f:r den Subselect ALL zum Ein-
satz.
JOIN
JOIN ... ON Verbindungen zwischen Tabellen werden typischerweise mit JOIN
hergestellt. Auf JOIN wird weiter unten noch ausf:hrlich einge-
gangen. Das folgende Beispiel ermittelt zu jeder Bestellung auch
gleich den Namen des Bestellers:
Im folgenden Beispiel werden die Artikelnamen aus der Artikel- FULL OUTER JOIN
Tabelle zur:ckgegeben, zu denen noch keine Bestellung erfolgte.
Ein einfacher JOIN w:rde kein Ergebnis liefern, weil NULL-Zeilen
keine 5bereinstimmung bringen k@nnen.
Entfernen Sie die WHERE-Bedingung, sehen Sie alle Reihen der Ta- LEFT OUTER JOIN
belle Bestellungen. Um nun steuern zu k@nnen, ob die linke oder RIGHT OUTER JOIN
rechte Tabelle unbedingt angezeigt werden soll – also auch dann,
wenn NULL enthalten ist –, k@nnen Sie die Schl:sselworte LEFT und
RIGHT verwenden.
Tauschen Sie das Schl:sselwort LEFT gegen RIGHT aus, wird der LEFT JOIN
Prozess entsprechend zuerst auf die rechte Tabelle angewandt. RIGHT JOIN
Die entsprechenden Reihen aus der linken Tabelle sind dann NULL.
Je nach Umfang der Daten sieht das dann folgendermaßen aus:
Sandini Bib
420 5 Grundlagen der Datenspeicherung
Korrelierende Komplexe Abfragen mit JOIN sind oft sinnvoll und vereinfachen
Namen den Code. Sie sind aber kein Allheilmittel gegen haarstr,ubende
WHERE-Bedingungen. Oft verliert man den 5berblick allein durch
Nennung mehrerer Tabellennamen, die zur eindeutigen Adressie-
rung der Felder geschrieben werden m:ssen. Hilfreich ist ein wei-
teres Schl:sselwort: CROSS JOIN.
CROSS JOIN Bei der Verbindung von zwei Tabellen kann auch ein Zugriff auf
beide Spaltens,tze der Tabellen (oder mehrerer Tabellen) erfor-
derlich sein. CROSS JOIN erledigt dies:
SELECT * FROM Artikel CROSS JOIN Adressen
Im Ergebnis erhalten Sie alle Spalten von beiden Tabellen und ei-
ne Mischung aus jeder mit jeder Spalte (die man mit WHERE sinnvoll
einschr,nken kann). Gleiche Spaltennamen werden :bernommen.
Wenn Sie gezielt darauf zugreifen m@chten, sollten numerische
Spaltenindizes verwendet werden.
Sandini Bib
Transact-SQL – SQL mit dem SQL Server 2000 lernen 421
UNION
Manchmal gibt es keine M@glichkeit, in einer einzige Abfrage alle UNION
Daten zu ermitteln. Dann m:ssten Sie die Abfragen einzeln erstel-
len, die Daten in eine Programmier- oder Skriptumgebung :berf:h-
ren und dort Datensatzweise kombinieren. Alternativ k@nnen Sie
SELECT-Befehle mit dem Schl:sselwort UNION kombinieren. Das
Ergebnis entspricht dann der Summe oder Kombination der Ab-
fragen. Oft kann UNION durch eine WHERE-Bedingung und den Opera-
tor OR ersetzt werden. Kombinieren lassen sich nur die Ergebnisse
von zwei zueinander kompatiblen Spalten. So sind beispielsweise
SMALLINT und INT kompatibel, DATETIME und CHAR dagegen nicht.
E RAW
Mit dieser Option wird das Abfrageergebnis in Zeilen mit dem
generischen Tag <row/> festgelegt. Eine dreispaltige Tabelle s,-
he in XML dann folgendermaßen aus:
<row CustomerID="ALFKI" OrderID="10643"
OrderDate="1997-08-25T00:00:00"/>
<row CustomerID="ANATR" OrderID="10308"
OrderDate="1996-09-18T00:00:00"/>
E AUTO
Diese Methode gibt einen einfachen XML-Baum zur:ck. Das
ist sinnvoll, wenn mehrere Tabellen abgefragt werden.
<Customers CustomerID="ALFKI" ContactName="Maria Anders">
<Orders OrderID="10643"/>
<Orders OrderID="10692"/>
<Orders OrderID="10702"/>
<Orders OrderID="10835"/>
<Orders OrderID="10952"/>
<Orders OrderID="11011"/>
</Customers
E EXPLICIT
Diese Option definiert die Art und Weise der Gestaltung des
XML-Baumes. Die Bildung der Tag-Struktur basiert auf der
Angabe von Alias-Namen mit einer sehr speziellen Syntax.
Alle drei Parameter lassen sich noch mit einem Modifikator ver-
kn:pfen, der die Ausgabe steuert:
E ELEMENTS
Hiermit wird erzwungen, dass alle Spalten als Elemente (Tags)
dargestellt werden, nicht als Attribute.
Sandini Bib
Transact-SQL – SQL mit dem SQL Server 2000 lernen 423
E BINARY BASE64
Bin,rdaten werden mit dieser Option im Base64–Format dar-
gestellt. Beim Parameter AUTO ist dies die Standardeinstellung,
bei EXPLICIT und RAW muss die Option explizit gesetzt werden.
E XMLDATA
Hiermit wird ein XML Schema mit der Beschreibung der Da-
tentypen erzeugt und dem Dokument vorangestellt.
Sichten im Detail
Sichten bilden letztlich nur mehr oder weniger komplexe SELECT-
Abfragen ab. Vor der Definition einer Sicht sollte Ihre Applikation
mit entsprechenden SELECT-Befehlen einwandfrei funktionieren.
Das folgende Kommando zeigt eine typische Abfrage, die die Na-
men der Artikel mit Bestellungen der letzten f:nf Tage anzeigt:
CREATE VIEW M@chten Sie diese Abfrage als Sicht verf:gbar machen, definieren
Sie zuerst eine Sicht mit dem Befehl CREATE VIEW:
Es liegt nahe, dass sich Sichten mit einem DROP-Befehl wieder l@- DROP VIEW
schen lassen:
Um eine Sicht neu zu definieren, wenn sich etwas ,ndert, verwen- ALTER VIEW
den Sie den Befehl ALTER VIEW. Die Anwendung entspricht exakt
CREATE VIEW; der angegebene Name der Sicht muss bereits existieren.
Batchprogrammierung
Es ist in T-SQL m@glich, kleine Programme zu schreiben, die sich GO
von außen oder automatisch starten lassen. Damit vereinfacht sich
die Programmierung der Skripte und der SQL Server 2000 ist im
Regelfall schneller als bei der Auswertung von Daten durch
Skript- oder Programmiersprachen. Wenn Sie SQL-Befehle direkt
an der Konsole eingeben, k@nnen Sie mehrere Befehle untereinan-
der schreiben und dann die Abarbeitung ausl@sen. Tritt ein Fehler
in einem der Befehle auf, stoppt der SQL Server 2000 die Ausf:h-
rung ganz. Wenn Sie das verhindern m@chten, k@nnen Sie Batch-
programme mit dem Befehl GO trennen. Jeder Teilabschnitt wird
abgearbeitet, bis in einem Abschnitt ein Fehler auftritt. Erst dann
wird abgebrochen. Die bis dahin abgearbeiteten Befehle bleiben
aber g:ltig.
Variablen
T-SQL kennt zwei Typen von Variablen: globale und lokale. Die
globalen werden vom SQL Server selbst erzeugt und k@nnen nicht
ge,ndert werden. Sie sind in allen Batchprogrammen verf:gbar.
Auch von außen – :ber ASP.NET-Programme – k@nnen Sie da-
rauf zugreifen. Die lokalen sind so wie alle Variablen selbst zu de-
finieren und k@nnen zur 5bertragung von Daten benutzt werden.
Sandini Bib
428 5 Grundlagen der Datenspeicherung
@@IDENTITY Globale Variablen sind sehr wichtig, denn Sie k@nnen damit die
@@ROWCOUNT am Anfang schon angesprochenen Verkn:pfungen steuern. Prak-
tisch wird im folgenden Beispiel ein neuer Datensatz in die Tabel-
le items geschrieben und der Wert des IDENTITY-Feldes item_id an-
schließend zur:ckgegeben:
Die andere wichtige Variable ist @@ROWCOUNT. Sie gibt die Anzahl der
behandelten Datens,tze der letzten Aktion zur:ck. Damit k@nnen
Sie pr:fen, wie viele Reihen von der Auswahl betroffen waren.
UPDATE Artikel SET preis = preis *1.2 WHERE preis < 100
SELECT @@ROWCOUNT
Sandini Bib
Transact-SQL – SQL mit dem SQL Server 2000 lernen 429
Zum Speichern von Daten gibt es lokale Variablen, die nur w,h- Lokale Variable
rend des Batchlaufes aktiv sind. Hier eine einfache Anwendung: mit DECLARE
erkl"ren
DECLARE @zahl INT
SELECT @zahl = 4+6
SELECT @zahl
Die Ausgaben einzelner Werte ist mit ADO.NET sehr einfach mglich.
Mehr Informationen darber finden Sie im Abschnitt 9.2.4, »SQL-Befeh-
le an die Datenbank senden« ab Seite 842. Suchen Sie dort nach der Me-
t
thode ExecuteScalar.
Kommentare
Sie k@nnen auch in SQL-Programmen Kommentare anbringen. In-
nerhalb der Zeile beginnt der Kommentar mit zwei Minuszeichen
»––» und außerhalb mit /*. Ebenso endet der Kommentar mit */.
Sie k@nnen nat:rlich auch jede Zeile immer wieder mit den zwei
Minus-Zeichen beginnen lassen.
ELSE Wenn Sie statt des Vergleichswerts 3 die Zahl 100 eingeben, wird
NULL zur:ckgegeben, wenn die Tabelle weniger als 100 Datens,tze
enth,lt. Mit ELSE k@nnte die Konstruktion so aussehen:
Das Schl:sselwort ELSE ist optional und wird nur eingesetzt, wenn
es tats,chlich um eine alternative Verzweigung geht.
BEGIN ... END Bemerkenswert ist, dass es f:r die Zusammenfassung von Bl@-
cken keine Klammern wie in C# oder ein Then-Schl:sselwort wie
in VB.NET gibt. Stattdessen deklarieren Sie Bl@cke mit BEGIN ...
END. Der nach der Bedingung stehende Befehl wird ausgef:hrt,
wenn die Bedingung wahr ist:
Der letzte SELECT-Befehl gibt das Ergebnis aus. Beachten Sie das
Gleichheitszeichen vor dem CASE. Es geh@rt zum SELECT-Befehl.
Das folgende Beispiel zeigt, wie man mit CASE komfortable Aus-
wahlm@glichkeiten realisiert.
Damit wird eine Tabelle ausgegeben, die f:r einige Artikel eine
weiterf:hrende Beschreibung enth,lt. Sie k@nnen statt der Aus-
gabe auf dem Bildschirm ebensogut die neuen Werte in eine ande-
re Tabelle kopieren. Nat:rlich lassen sich auch die zugewiesenen
Werte in Variablen :bertragen und von dort aus weiterverarbei-
ten, ebenso werden in der Praxis auch die 5bersetzungen aus ei-
ner anderen Tabelle stammen.
RETURN
RETURN Um ein Batchprogramm zu verlassen, gibt es den Befehl RETURN.
Bauen Sie diesen Befehl in eine Bedingung ein:
IF DATENAME(mm,GETDATE())="Feb" RETURN
5.5.10 Transaktionen
Viele Prozesse, die im Internet mit Datenbanken bearbeitet wer-
den, sind kritische Vorg,nge mit Kreditkartentransaktionen, Zu-
griffen auf Gateways der Geldinstitute oder Abgleich kostbarer
Kundendaten. Auch Webserver bestehen nur aus normalen Com-
putern und unterliegen St@rungen und technischen Problemen. Es
besteht so immer die M@glichkeit, dass Sie eine Tabelle @ffnen, et-
was schreiben und dann die korrespondierende Tabelle @ffnen
und auch etwas schreiben. Genau da st:rzt der Computer ab. Jetzt
Sandini Bib
Transact-SQL – SQL mit dem SQL Server 2000 lernen 433
BEGIN TRANSACTION
INSERT Artikel (name, nummer, preis)
VALUES ('Sonderanfertigung', '9999', 19.99)
INSERT Bestellungen ([k-id], [a-id], menge, summe)
VALUES (4, @@IDENTITY, 1, 19.99)
COMMIT TRANSACTION
Anders sieht die Anwendung aus, wenn auch die Fehler beachtet
werden sollen, die bei laufendem Betrieb auftreten k@nnen. Hier-
zu werten Sie den Fehlercode aus:
BEGIN TRANSACTION
INSERT Artikel (name, nummer, preis)
VALUES ('Sonderanfertigung', '9999', 19.99)
INSERT Bestellungen ([k-id], [a-id], menge, summe)
VALUES (2, @@IDENTITY, 1, 19.99)
IF @@ERROR = 0
COMMIT TRANSACTION
ELSE
ROLLBACK TRANSACTION
SELECT @@ERROR AS Fehlermeldung
Sandini Bib
434 5 Grundlagen der Datenspeicherung
EXECUTE AlleNamen
Der Name der Prozedur muss eindeutig sein. Sie k@nnen nat:rlich DROP PROCEDURE
mehrere Befehle in der Prozedur speichern. Sind Sie fertig, spei-
chern Sie die Prozedur. <nderungen sind mit ALTER PROCEDURE
m@glich. Wollen Sie unbedingt etwas ,ndern, l@schen Sie die Pro-
zedur, und legen Sie sie neu an:
EXECUTE EinigeNamen 3
ALTER PROCEDURE Um eine Prozedur ,ndern zu k@nnen, verwenden Sie den Befehl
ALTER PROCEDURE. Die Syntax entspricht exakt CREATE; geben Sie ein-
fach eine neue Definition an.
EXECUTE Beim Aufruf mit EXECUTE werden die Parameter einfach hinter den
Namen geschrieben:
EXECUTE EinigeName 3
Der Aufruf ist ,hnlich der Prozedur ohne R:ckgabewert, nur das
Schl:sselwort OUTPUT muss mit angegeben werden.
Der Befehl PRINT ist nur sinnvoll, wenn der SQL Server eine Aus-
gabekonsole hat, beispielsweise wenn Sie den Query Analyzer verwen-
den. In anderen Umgebungen gehen die mit PRINT erzeugten Ausgaben
verloren. Sie knnen die Ergebnisse auf diesem Wege nicht nach
ASP.NET transportieren.
Funktionen
CREATE FUNCTION Funktionen werden mit CREATE FUNCTION erzeugt. Der enthaltene
Code entspricht den Prozeduren, ebenso die Verwendung. Der
R:ckgabewert wird mit der Klausel RETURNS festgelegt. Im Gegen-
satz zu Prozeduren kann mit RETURNS TABLE auch die R:ckgabe ei-
ner Tabelle erfolgen.
5.5.12 Trigger
Als kleine Automaten in T-SQL k@nnte man Trigger bezeichnen.
Mit diesen Funktionen automatisieren Sie Prozesse auf einfachste
Art und Weise. Vor allem f:r globale Einschr,nkungen sind Trig-
ger pr,destiniert. Trigger arbeiten ,hnlich wie die Ereignisse in
.NET, sind aber vergleichsweise primitiv.
Einfhrung in Trigger
TRIGGER Unter dem Stichwort Trigger (dt. Ausl@ser) werden Prozeduren
verstanden, deren Start nicht von der Eingabe oder der Ausf:h-
rung eines Befehles abh,ngt, sondern von Ereignissen. Trigger
werden also nicht von einem Skript aus gestartet, sondern mit be-
stimmten Zust,nden und Bedingungen verbunden und starten
dann bei Bedarf direkt im SQL-Server.
T-SQL kennt auch den Befehl ALTER TRIGGER, mit dem Sie eine Defi-
nition wiederholen k@nnen, ohne den DROP TRIGGER-Befehl zuvor
einsetzen zu m:ssen.
Trigger-Praxis
Ein praktisches Beispiel soll zeigen, wie Sie Trigger in realen Da-
tenbankprojekten einsetzen k@nnen und damit die Programmie-
rung der umgebenden Skripte vereinfachen. Der folgende Trigger
berechnet die Gesamtmenge der Artikel bei einer neuen Bestel-
lung:
Der Trigger startet nur einmal, auch wenn mit einem INSERT-
Befehl mehrere Datens,tze betroffen sind. Der Trigger startet auf-
grund des Auftretens des INSERT-Befehls, nicht aufgrund dessen
Effektes.
Triggertabellen Um feststellen zu k@nnen, welche Aktion den Trigger wirklich
nutzen ausgel@st hat, reichen die bisherigen Informationen nicht aus.
DELETE- oder UPDATE-Befehle werden bei großen Programmen hun-
dertfach benutzt, und immer wieder wird der Trigger ausgel@st.
Der folgende Trigger speichert beispielsweise jeden gel@schten
Ansprechpartner in einer Sicherheitstabelle:
Der Trick ist die Verwendung der Tabelle deleted. Diese wird au-
tomatisch mit jedem DELETE angelegt, wenn ein Trigger definiert
ist. Ebenso gibt es eine Tabelle inserted, die nur dann vorhanden
ist, wenn der Befehl INSERT arbeitet und ein assoziierter Trigger
existiert. Wann immer Sie die gesamte Tabelle mit DELETE partner
l@schen, wird die Spalte name komplett nach Tabelle logdata ko-
piert. Grunds,tzlich k@nnen Sie damit leicht Protokolldateien f:r
Ihren SQL Server erzeugen. Den Zustand der beiden Tabellen fin-
den Sie in der folgenden Liste:
Tricks mit Triggern Raffiniert ist die Kombination aus Trigger und Transaktion. Der
folgende Trigger verhindert <nderungen an der Datenbank am
Wochenende:
Sandini Bib
Praktische Einf,hrung in XML 441
Trotz dem Fokus auf »Lesen« kann mit .NET XML auch erzeugt
werden. Dies geht aber eher in den Bereich des Umgangs mit Da-
ten allgemein hinein und soll sp,ter noch genauer betrachtet wer-
den.
Zum Speichern von Konfigurationen wird XML bereits eingesetzt; Speichern von
die Dateien web.config und machine.config basieren bereits auf der- Konfigurationen
sich XML daf:r an. <ndern sich die Daten, laden Sie die aktuali-
sierte Konfigurationsdatei per FTP oder WebDAV auf den Server
und die Applikationen ber:cksichtigt das entsprechend.
Datenquelle f4r Geht man etwas weiter in den 5berlegungen, k@nnen auch
Steuerelemente HTML-Fragmente konfiguriert werden. So sind relativ h,ufig
Listfelder (<select>-Tags) im Einsatz. Diese lassen sich gut per
XML f:llen. Da XML als Datenquelle dienen kann – analog zu ei-
nem relationalen Datenbankmanagementsystem – ist der Einsatz
mit Webserver-Steuerelementen sehr einfach.
Verarbeitungsprinzipien
Aus der Aufgabenstellung ergeben sich verschiedene Strategien,
wie die Daten eines XML-Dokumentes verarbeitet werden k@n-
nen. Vereinfacht kann das auf zwei Varianten reduziert werden:
Push: SAX Das sequenzielle Lesen wird von zwei Mechanismen verwendet.
Einer wird als SAX(Simple API for XML) bezeichnet. Dies ist eine
Schnittstelle zu XML-Dokumenten, die Programme implementie-
ren k@nnen. SAX ist ein so genanntes Push-Modell. Der Parser
Sandini Bib
Praktische Einf,hrung in XML 443
Alternativ kann ein Pull-Modell verwendet werden. Dabei fordert Pull: XmlReader
das Programm den n,chsten Knoten explizit vom Parser an. Die
XmlReader-Implementierung in .NET basiert auf diesem Prinzip.
Wie SAX ist auch dieses Modell lediglich zum Vorw,rtslesen in
der Lage. Vorteilhaft ist die hohe Geschwindigkeit und der gute
Umgang mit sehr großen Datenmengen, denn es ist nicht notwen-
dig, mehr als einen Knoten im Speicher zu halten. Wenn nur klei-
ne Datenmengen aus großen Dokumenten ben@tigt werden oder
der gesamte Inhalt gelesen werden muss, ist XmlReader die beste
Wahl. Die Implementierung des allgemeinen Modells in .NET ist
um einige Methoden erweitert worden, mit denen sich der Einsatz
von DOM oft vermeiden l,sst.
V@llig anders arbeitet das Objektmodell, als DOM (Document Ob- DOM:
ject Model) bezeichnet. Dabei wird das gesamte Dokument gelesen XmlDocument
5.6.2 XML-Grundlagen
Die Theorie hinter XML ist weder ungew@hnlich komplex noch
unverst,ndlich. Dennoch sind ein paar Grundlagen f:r den prak-
tischen Einsatz zu beachten, wenn Sie nicht mit Leistungseinbr:-
chen oder unhandlichem Code konfrontiert werden m@chten.
Auf der anderen Seite steht ein Lager, dessen Anh,nger einen
datenzentrierten Ansatz als Haupteinsatzgebiet von XML se-
hen. Hier wird davon ausgegangen, dass k:nftig die :ber-
ragende Mehrheit der XML-Dokumente automatisch erzeugt
und auch automatisch gelesen wird; der Mensch also nur sel-
ten reines XML zu sehen bekommt. Daten in XML sind nicht
immer so groß wie reine Texte und die Software zur Verarbei-
tung ist Bestandteil der meisten modernen Parser.
<eintrag>
Lieschen M2ller
<telefon>030--12345678</telefon>
<handy>0177--9876543</handy>
</eintrag>
<eintrag>
<name>Lieschen M2ller</name>
<telefon>030--12345678</telefon>
<handy>0177--9876543</handy>
</eintrag>
Je feiner Sie die Struktur beschreiben, umso einfacher wird die Auswahl
von Teilen bei der Transformation und Darstellung. »4bertriebene«
Feinheit kann jedoch zu unbersichtlichen und schwer handhabbaren
t
Dokumenten fhren.
Nun ist auch dies noch nicht perfekt, denn eine Abfrage bestimm- Inhalt beschreiben
ter Teilmerkmale bereitet immer noch Probleme. Die Auswahl des
Nachnamens ist kaum zuverl,ssig m@glich und eine Liste aller Te-
lefontypen, unabh,ngig davon, ob es sich um Festnetz- oder Mo-
biltelefone handelt, ist nur schwer m@glich. Durchaus denkbar ist,
dass sich die Anzahl an Typen sp,ter erh@ht, was massive <nde-
rungen in Transformationsanweisungen zur Folge h,tte. Eine bes-
sere Basis f:r den n,chsten Schritt w,re folgende Version:
<eintrag>
<name>
<vorname>Lieschen</vorname>
<nachname>M2ller</nachname>
</name>
<telefon>030--12345678</telefon>
<telefon>0177--9876543</telefon>
</eintrag>
Eine exakte Beschreibung des Inhalts vermeidet Fehler und verbessert die
automatisierte Verarbeitung. Der Computer »lernt« anhand der Aus-
zeichnung der Inhalte mit Tags deren Bedeutung kennen. Je feiner die
t
Inhaltsbeschreibung, umso h>ufiger knnen Informationen direkt abge-
rufen werden. 4bertriebene Markierung kann zu komplizierteren Trans-
formationsprogrammen fhren.
<eintrag>
<name>
<vorname>Lieschen</vorname>
<nachname>M2ller</nachname>
</name>
<telefon type="telekom">030--12345678</telefon>
<telefon type="eplus">0177--9876543</telefon>
</eintrag>
Jetzt kann jedes Element direkt mittels XPath – sp,ter folgt mehr
dazu – aus dem Datenstrom extrahiert werden. Durch die Attribu-
te lassen sich Daten auch gut filtern. Attribute beschreiben Zu-
st,nde oder definieren Modifikationen. Sie sollten eindeutig, ein-
malig und in geringer Zahl vorhanden sein. Folgende Definition
ist nicht zu empfehlen:
<tag a1="n1" a2="n2" a3="n3" .../>
<tag>
<a1>n1</a1>
...
Als Antwort auf XDR und den Bedarf nach einem offenen Stan- XSD
dard, der die Nachteile von DTDs vermeidet und in der Zukunft
erweiterbar ist, wurde XSD entwickelt. XSD steht f:r XML Sche-
ma Definition Language, oft auch kurz als »Schema« bezeichnet.
Diese Form der Grammatikbeschreibung ist selbst in XML ge-
schrieben. Der Standard ist beim W3C verabschiedet.
Sandini Bib
450 5 Grundlagen der Datenspeicherung
Darin eingebettet sind die Element- und Typdefinitionen. Der Na- Namensraum
mensraum, der verwendet wird, heißt bei VS.NET »xs«, bei der
W3C-Empfehlung ist »xsd« im Einsatz. Allerdings ist der Na-
mensraum ohnehin w,hlbar – im Unterschied zu XDR.
Elemente werden folgendermaßen definiert:
<xs:element name="elementname"></xs:element>
<xs:complexType name="newscontenttype">
<xs:sequence>
<xs:element name="title" type="xs:string" />
<xs:element name="text" type="xs:string" />
</xs:sequence>
<xs:attribute name="date" type="xs:date" />
</xs:complexType>
Dieser Typ definiert einen Datentyp mit dem Namen »newscon- Element- und
tenttype«. Enthalten darf ein Tag, das diesen Datentyp tr,gt, eine Typdefinitionen
unbegrenzte Folge (xs:sequence) der Elemente <title> und <text>.
Außerdem tr,gt das Tag ein Attribut mit dem Namen date und
dem Datentype xs:data. Ein XML-Dokument, das dieser Gramma-
tik entspricht, kann also folgende Strukturen enthalten:
<newscontent date="13.4.2002">
<title>Titel steht hier</title>
<text>Hier folgt der Text</text>
</newscontent>
Die Nutzung des komplexen Typs ist auf zwei Wegen m@glich.
Zum einen kann die Definition abstrakt erfolgen, außerhalb aller
Elementdefinitionen. Dann wird auf den Typ an der Stelle verwie-
sen, an der der Datentyp festgelegt wird:
<xs:element name="news" type="newscontenttype">
Sandini Bib
452 5 Grundlagen der Datenspeicherung
Alternativ wird die Definition direkt eingebettet. Das ist vor allem
dann sinnvoll, wenn der Typ nur an dieser einen Stelle verwendet
wird:
<xs:element name="news">
<xs:complexType name="newscontenttype">
<xs:sequence>
<xs:element name="title" type="xs:string" />
<xs:element name="text" type="xs:string" />
</xs:sequence>
<xs:attribut name="date" type="xs:date" />
</xs:complexType>
</exs:element>
Damit ist die Reihenfolge und das Auftreten der Elemente starr fest-
gelegt. M@chten Sie eine beliebige Folge definieren, hilft xs:choice:
<xs:complexType name="newscontenttype">
<xs:choice>
<xs:element name="title" type="xs:string" />
<xs:element name="text" type="xs:string" />
</xs:choice>
</xs:complexType>
Anzahl der Die Anzahl der Elemente kann ebenso einfach festgelegt werden.
Elemente Dazu wird die Elementdefinition um die Attribute minOccurs und
maxOccurs erg,nzt:
Hier wird festgelegt, dass der Titel (<title>) genau ein Mal auftre-
ten darf, w,hrend der Textblock <text> optional ist und unbe-
grenzt wiederholt werden kann.
<xs:all>
<xs:element name="text" type="xs:string"/>
<xs:element name="picture" type="xs:href"/>
</xs:all>
Attribute wurden bereits kurz angesprochen. Sie werden wie Ele- Attribute
mente definiert, stehen aber in komplexen Definitionen immer
nach allen xs:sequence-, xs:choice- oder xs:all-Definitionen.
Das Attribut use wird hier verwendet, um die Angabe eines Attri-
butes »encoding« im Tag zu erzwingen. Mit base wird der Basis-
typ festgelegt, auf dem die zul,ssigen Parameter basieren. Bei "on"
und "off" handelt es sich zwangsl,ufig um Zeichenketten.
E <xs:minInclusive value="1">
Diese Definition ist f:r Zahlenwerte interessant und definiert
den kleinsten Wert eines Ganzzahlbereiches.
E <xs:maxInclusive value="100">
Mit dieser Definition wird der maximale Wert eines Ganzzahl-
bereiches festgelegt.
E <xs:length value="5"/>
Bei Zeichenketten kann die L,nge begrenzt werden, die die
Zeichenkette annehmen darf.
E <xs:pattern value="[a-z._]+@[a-z.]\.[a-z]{2,4}"/>
Komplexere Bedingungen lassen sich mit regul,ren Ausdr:-
cken festlegen.
Sandini Bib
454 5 Grundlagen der Datenspeicherung
Beachten Sie, dass dies nur eine sehr kompakte und stark vereinfachende
Darstellung von XSD war. Es sollte aber ausreichend sein, um die mit
VS.NET erzeugten Dokumente zu interpretieren oder fr einfache An-
wendungen ein Schema zu schreiben, wenn VS.NET nicht zur Ver-
fgung steht.
Eine Warnung ist wichtig, wenn Sie mit VS.NET arbeiten: XSD wurde
von Microsoft etwas erweitert, das heißt, es stehen mehr Typen und Ele-
mente zur Verfgung, als der Standard verlangt. Dies ist darin begrn-
det, dass mit XML-Dokumenten Daten aus relationalen Datenbanken
abgebildet werden sollten. DataSet verwenden in der internen Darstel-
lung immer XML, egal wie Ihre Datenquelle aussieht. XSD kann aber
nicht alles abbilden, was in SQL Server oder Access mglich ist. Die Er-
weiterungen lsen das Problem. Fr den Import fremder XSD-Dateien
stellt dies kein Problem dar. Umgekehrt knnen Informationen aus der
Definition verloren gehen.
Damit d:rfte das Format hinreichend flexibel sein. Den Titel als
Attribut zu definieren, erscheint nicht g:nstig. Sp,tere Versionen
k@nnten mit Untertiteln arbeiten, dann w,re auf jeden Fall ein Ele-
ment erforderlich – Attribute sind Endpunktknoten. Beim Datum
werden kaum Teile von Interesse sein. Weitere Datumsangaben –
wie ein in der Zukunft liegendes Datum, ab dem die Information
aktiv wird – lassen sich gut als weitere Attribute definieren.
Im letzten Abschnitt wurden bereits theoretische Ausf:hrungen zu XML und XSD im
XSD gezeigt. Sie sollten die starke Unterst:tzung in Visual Studio Visual Studio .NET
.NET f:r XML und Schema nutzen, um gleich ein professionelles
Datenregime aufzubauen. Legen Sie also zuerst eine XSD-Datei an:
1. F:gen Sie Ihrem Projekt ein neues XML-Schema hinzu. Dazu
w,hlen Sie im Kontextmen: Hinzufgen | Neues Element
hinzufgen.
2. Im folgenden Dialog suchen Sie das Symbol XML-Schema.
3. Nennen Sie die Datei news.xsd.
Es erscheint eine leere Fl,che, auf der Sie nun die Struktur der
XML-Daten bestimmen k@nnen. Wenn Sie sp,ter Daten hinzuf:-
gen, wird die Validierung des Dokuments auf der Grundlage die-
ser Schema-Datei erfolgen.
Zuerst ziehen Sie ein Element aus der Toolbox am linken Rand
auf die Fl,che. Benennen Sie es mit »news« im linken Feld der An-
zeige und schreiben Sie »NewsType« auf die rechte Seite, wo der
Datentyp zugeordnet wird. Da dieses oberste Element nur weitere
eigene Elemente enth,lt, ist dies ein benutzerdefiniertes Format.
Ziehen Sie nun ein Element vom Typ »element« auf das Rechteck,
das den neuen komplexen Typ bildet: »newscontent«. Schreiben
Sie als Datentyp nun »newscontenttype« hinein. Der Name ist
wahlfrei – solange er eindeutig ist – und wird nachfolgend zur
Definitionen eines »ComplexType« verwendet.
Ziehen Sie jetzt ein Element vom Typ »ComplexType« aus der
Toolbox auf die freie Fl,che und benennen Sie es »NewsType«.
Dieser komplexe Typ enth,lt die eigentlichen Elemente. Dazu er-
zeugen Sie in der Liste, entweder durch Auswahl eines Typs am
linken Rand der Definitionsfl,che oder durch Drag&Drop aus der
Toolbox die ben@tigten Elemente »title« und »text« sowie das At-
tribut »date«. Dem Attribut »date« geben Sie als Datentyp date,
den anderen Elementen string.
Eine neue XML-Datei f:gen Sie wie jede andere Datei im Projekt-
Explorer hinzu. Vergeben Sie hier den Namen news.xml. Ist die
Datei erzeugt, wird sie angezeigt. Bis auf den XML-Kopf ist nichts
enthalten. Mit (F4) gelangen Sie zum Eigenschaften-Dialog. W,h-
len Sie dort die Gruppe DOCUMENT aus, falls sie nicht ohnehin
bereits vorgegeben ist. In der Zeile targetSchema k@nnen Sie
nun die XSD-Datei mitsamt dem Standardpr,fix http://tempuri.org
ausw,hlen.
Der Zugriff auf die im Web abgelegten Datendateien – dies betrifft Zugriff auf Daten-
sowohl news.xsd als auch news.xml – erfolgt :ber die Berechnung dateien
s = Server.MapPath("data")
s = s & "\" & newsfile
Return s
End Function
dsNews.ReadXmlSchema(sCurrentSchema)
newsRepeater.DataSource = dsNews
newsRepeater.DataMember = "newscontent"
newsRepeater.DataBind()
Nun ist es an der Zeit, die XML-Datei mit ein paar Zeilen zu f:llen
und das Programm auszuprobieren, was zu etwa folgendem Er-
gebnis f:hrt:
Sandini Bib
XML mit .NET verarbeiten 461
Abbildung 5.26: Die News-Ausgabe mit den Daten aus der XML-Datei in Aktion
Wie nicht anders zu erwarten war, hat Microsoft eine sehr umfas-
sende direkte Unterst:tzung f:r XML ins .NET-Framework im-
plementiert. Die Basis bildet der Namensraum System.Xml. F:r den
Zugriff via DOM dienen die Klassen aus System.Xml.XPath und f:r
Transformationen System.Xml.Xsl. Informationen zu XPath finden
Sie in Abschnitt 5.8, »Daten suchen mit XPath« ab Seite 470, w,h-
rend Transformationen mit .NET in Abschnitt 5.9, »Daten trans-
formieren mit XSLT« ab Seite 478 behandelt werden.
2 Das ist so nicht ganz korrekt. Die XML-Klassen werden tats,chlich verwen-
det, allerdings erledigte dies das Framework intern. Diese »heimliche« Nut-
zung von XML ist sehr umfassend, entsprechende Kenntnisse dar:ber er-
leichtern das Verst,ndnis f:r viele allt,gliche Vorg,nge.
Sandini Bib
462 5 Grundlagen der Datenspeicherung
E XmlTextReader
Dies ist die einfachste Implementierung, die nicht mehr bereit
stellt als die Basisklasse selbst.
E XmlValidatingReader
Mit dieser Klasse kann zus,tzlich die G:ltigkeitspr:fung auf
der Basis eines Schematas vorgenommen werden. Die Ver-
arbeitung ist deshalb geringf:gig langsamer.
E XmlNodeReader
Diese Klasse erlaubt das Lesen eines Knotens auch dann, wenn
es sich um eine Teilstruktur eines Dokumentes handelt, wie sie
vom DOM des Dokuments abgeleitet werden kann. Eine G:l-
tigkeitspr:fung wird nicht unterst:tzt.
Der Konstruktor der Klasse erlaubt die Angabe eines Pfades zur Wie es
XML-Datei. Er besitzt viele 5berladungen, sodass der Umgang funktioniert
mit anderen Datenquellen ohne weiteres m@glich ist. Von Interes-
se ist die Angabe eines Objekts einer der Stream-Klassen, wie bei-
spielsweise FileStream oder TextReader.
Abbildung 5.27: Erster Teil des XML-Dokuments news.xml aus dem letzten Abschnitt
Das sequenzielle Lesen erlaubt den Zugriff auf alle Knoten. Dabei Umgang mit
ist an der Ausgabe des letzten Beispiels zu erkennen, dass auch die Whitespaces
Leerr,ume (allgemein als »Whitespaces« bezeichnet) zwischen
Tags als Elemente erkannt werden. Prinzipiell ist es nicht notwen-
dig, bei der Verarbeitung von XML auf die Leerr,ume zu achten,
denn sie sind zur Trennung nicht zwingend notwendig. Die weitere
Verarbeitung kann aber darauf R:cksicht nehmen. Wenn die Aus-
gabe von XML k:nftig auch f:r Menschen lesbar sein soll, ohne
dass eine explizite Transformation in ein typischerweise f:r Men-
schen geeignetes Format stattfindet, ist der Erhalt von Einr:ckun-
gen, Trennfeldern und Zeilenumbr:chen durchaus angeraten.
Die Klasse XmlWriter1 muss nun zwei Dinge erledigen: Lesen einer
Dateihierarchie und Versenden als XML. Der Startpunkt im Datei-
system kann mit einem GET-Parameter festgelegt werden, sodass
die L@sung auch in dieser Hinsicht universell ist. Zuerst ein Blick
auf die Page_Load-Methode, in der die Verarbeitung beginnt:
xWrite.WriteStartDocument ()
xWrite.WriteStartElement("dirlist")
Dieses Element erh,lt ein Attribut, das den Pfad enth,lt und fol-
gendermaßen erzeugt wird:
In ReadDir steckt die eigentliche Funktionalit,t. Zuerst das Listing Das Dokument
dieser Methode auf einen Blick: erzeugen
Next
Catch
xWrite.WriteStartElement("error")
xWrite.WriteString("Verzeichnis nicht gefunden")
xWrite.WriteEndElement()
Finally
xWrite.WriteEndElement()
End Try
End Sub
Listing 5.6: Lesen einer Verzeichnishierarchie und Schreiben der XML-Daten
(Fortsetzung des Ausschnitts aus XmlWriter1.aspx.vb)
Wie es Die Methode arbeitet rekursiv, wobei das Erzeugen der XML-Tags
funktioniert jeweils am Anfang erfolgt; am Ende wird das Tag dann geschlos-
sen (WriteEndElement). Bei Dateizugriffen kommt es h,ufig vor,
dass Pfadangaben nicht stimmen. Deshalb wird noch eine Try-
Catch-Finally-Anweisung verwendet, die sicherstellt, dass auch im
Fehlerfall g:ltiges XML erzeugt wird. Die folgende Abbildung
zeigt, wie der Internet Explorer diesen Fehlerzustand anzeigt.
Abbildung 5.28: Ausgabe eines »Fehlerdokuments« bei einem nicht vorhandenen Pfad
Abbildung 5.29: Teil einer umfassenderen Ausgabe, die das gezeigte Programm erzeugt
Sandini Bib
468 5 Grundlagen der Datenspeicherung
</li>
</xsl:template>
</xsl:stylesheet>
Listing 5.7: XSLT-Datei zur Transformation der automatisch erzeugten Ergebnisse
(ShowFiles.xslt, im Stammordner des Projekts)
<h1><xsl:value-of select="./@path"/></h1>
<ul><b><xsl:value-of select="./@name"/></b><br/>
Die Ausgabe, mit etwas CSS verfeinert, zeigt Abbildung 5.30. Inte-
ressant am Zusammenspiel der erzeugten XML-Daten und des
XSLT-Stylesheets ist die Tatsache, dass bei der Transformation of-
fensichtlich rekursiv gearbeitet wird. Gerade hierarchische Struk-
turen, die beliebig verschachtelt sein k@nnen, sind mit prozedura-
len Programmen nicht ganz so einfach zu verarbeiten.
Dies soll vor allem als Anregung daf:r dienen, XML als Trans-
port- oder Speichermedium in bestimmten F,llen bevorzugt als
Alternative zur konventionellen Programmierung zu erkennen.
Sandini Bib
470 5 Grundlagen der Datenspeicherung
XPath realisiert die Abfrage durch Beschreibung eines Pfades und Pfade zum Ziel
verzichtet dabei auf Schleifen oder andere zyklische Elemente.
Damit ist die Konstruktion zur Laufzeit und in Abh,ngigkeit vom
aktuellen Auftreten von Knoten zueinander m@glich. Wie der Na-
me der Sprache andeutet, ,hnelt die Auswahl von Knoten den
Pfadangaben im Dateisystem eines Betriebssystems. Das ist nahe
liegend, weil auch dort Daten hierarchisch angeordnet sind. Eine
typische XPath-Anweisung k@nnte also folgendermaßen aus-
sehen:
eintrag/name/vorname
Sie adressiert einen Knoten <vorname>, der Kind von <name> ist, was
wiederum Kind von <eintrag> sein muss:
<eintrag>
<name>
<vorname>
XPath-Knoten Darstellung
Wurzelknoten /
Elementknoten ElementName
Attributknoten @Attribut
Textknoten ., text()
Prozessinformation Nicht darstellbar
Namensraum alias:
Die XPath-Achsenbezeichner
Achsenbezeichner Achsenbezeichner k@nnen einen oder mehrere Knoten ausw,hlen.
Die konkrete Auswahl h,ngt vom aktuellen Knoten ab. Dies ist
zutreffend, wenn ein Dokument sequenziell durchlaufen wird.
Die folgende Tabelle zeigt alle Achsenbezeichner f:r Elemente auf
einen Blick. Elemente sind Tagnamen, also keine Attribute und
keine Namensraumbezeichnungen:
Wirkung der Es bietet sich an dieser Stelle an, die Wirkung der Achsenbezeich-
Achsenbezeichner ner mit einem Testprogramm zu lernen. Damit alle erdenklichen
Kombinationen auch getestet werden k@nnen, wird eine XML-
Datei entworfen, die entsprechende Achsen auch aufweist (siehe
Abbildung 5.31).
Diese Datei dient im folgenden Beispiel als Basis f:r die ersten
Programmierversuche mit .NET.
Next
currentLabel.Text += String.Join(", ", sa)
End Sub
Eine solche Liste ist ein Objekt der Klasse XmlNodeList. Hier wird
zuerst die Anzahl der Elemente mit Count ermittelt:
Dieses Array wird dann mit Join in die Liste umgewandelt und
dem Label-Steuerelement hinzugef:gt. Nun ist nat:rlich noch der
Aufruf interessant, der SelectNodes anwendet und die eben be-
schriebene Methode aufruft:
Das Feld sPath enthielt die Zeichenfolge »/A/C«, also einen ein-
fachen XPath-Ausdruck, der zum Element <C> hinf:hrt, damit die-
ses als Ausgangspunkt dienen kann. Der Ausdruck selektiert le-
diglich die Achse (achsenbezeichner::*), wobei das * zur Auswahl
aller Elemente der Achse f:hrt. In der Praxis k@nnten sich hier
Elementnamen anschließen, um die Auswahl einzuschr,nken, so-
wie eines oder mehrere Attribute, die auftreten oder bestimmte
Parameter aufweisen m:ssen.
E SelectNodes
Diese Methode gibt Knotenlisten aufgrund eines XPath-Aus-
drucks zur:ck. Der R:ckgabetyp ist XmlNodeList.
E SelectSingleNode
Diese Methode gibt nur den ersten Knoten der durch XPath er-
mittelten Knotenmenge zur:ck. Der R:ckgabetype f:r einen
Knoten ist XmlNode.
End Class
Listing 5.8: Rekursive Ausgabe des gesamten XML-Dokuments
(XmlDocumentNodes.aspx.vb)
Namensraumalias Durch die Erweiterung des Attributes xmlns wird der Namens-
raumalias festgelegt.
Einfache Vorlagen Zwischen den Wurzelelementen wird nun das Regelwerk auf-
gebaut. Eine zentrale Rolle spielt das Element <xsl:template>.
Templates (dt. Vorlagen) bilden die Stufen der eigentlichen Trans-
formation. Dabei gibt es zwei Arten von Templates. Zum einen
k@nnen sie durch eine XPath-Anweisung in ihrer Zust,ndigkeit
programmiert werden. Die folgende Regel zeigt, wie jedes Ele-
ment <name> zu einer Ausgabe im Ausgabedatenstrom f:hrt:
<xsl:template match="name">
<h1>NAME</h1>
</xsl:template>
<xsl:call-template name="regelname"/>
Text Soll explizit Text ausgegeben werden, der mit dem Editor nicht
darstellbar ist, muss das <xsl:text>-Element eingesetzt werden.
Das ist eigentlich – nach der Spezifikation – immer notwendig.
Die direkte Angabe von Text oder Tags ist eine Vereinfachung.
Beachten Sie, dass im Gegensatz zu VB.NET die Angabe hexadezi-
maler Codes in XSLT mit dem Pr,fix »0x« erkl,rt wird.
Sandini Bib
Daten transformieren mit XSLT 481
<xsl:template match="name">
Hier folgt ein Zeilenumbruch:<xsl:text>0x0A</xsl:text>
</xsl:template>
<xsl:template match="/">
<html>
<body>
<xsl:apply-templates />
</body>
</html>
</xsl:template>
<xsl:template match="B">
<xsl:value-of select="."/>
</xsl:template>
Sandini Bib
482 5 Grundlagen der Datenspeicherung
Attribute Beim Einsatz innerhalb einer Vorlage bezieht sich der Pfad, den
verwenden select akzeptiert, auf den :bergebenen Knoten, ist also relativ. Sie
k@nnen aber absolute Angaben verwenden. Der allein stehende
Punkt reflektiert in XPath den aktuellen Knoten, im Beispiel also
den Inhalt des Tags <B>. Auf eben diesem Wege werden auch At-
tribute gelesen. Das folgende Beispiel sucht nach Elementen vom
Typ <a> und gibt den Inhalt des Attributes href aus:
<xsl:template match="a">
<xsl:value-of select="@href"/>
</xsl:template>
<xsl:template match="a">
<img src="{@href}" />
</xsl:template>
<xsl:if test="@directory='hasfiles'">
Dieses Verzeichnis enth\lt Dateien
</xsl:if>
<xsl:choose>
<xsl:when test="attribute='archive'">Archiv</xsl:when>
Sandini Bib
Daten transformieren mit XSLT 483
<xsl:when test="attribute='compressed'">Compressed</xsl:when>
<xsl:when test="attribute='hidden'">Hidden</xsl:when>
<xsl:otherwise>
Unknown
</xsl:otherwise>
</xsl:choose>
Wollen Sie Listen von bestimmten Tags an einer Stelle ausgeben, Schleifen
ist <xsl:for-each> sehr praktisch. Schleifen im Sinne imperativer
Programmierung gibt es jedoch nicht, weil ver,nderliche Zust,n-
de nicht erlaubt sind:
<xsl:for-each select="name">
<a href="{.}"><xsl:value-of select="."/></a><br/>
</xsl:for-each>
Von Interesse ist oft auch eine Sortierm@glichkeit. Sie k@nnen da- Sortieren
zu innerhalb einer Schleife mit <xsl:sort> eine Anweisung platzie-
ren, die das zuverl,ssig erledigt:
<xsl:for-each select="name">
<xsl:sort select="." order="descending"/>
<a href="{.}"><xsl:value-of select="."/></a><br/>
</xsl:for-each>
Was Sie in XSLT nicht finden, sind die Anweisungen »for« und
»while«. Beide ben@tigen Variablen, deren Zustand sich ,ndert.
Das ist in funktionalen Sprachen nicht m@glich, weswegen die
Anweisungen nicht sinnvoll sind. Komplexere Schleifen werden
durch Rekursion (Selbstaufruf einer Vorlage) und Parameter er-
m@glicht. Oft ist dies kompakter als vergleichsweise imperative
Programme.
Variablen sind dennoch verwendbar, sie verhalten sich aber ,hn- Variablen
lich den Konstanten in anderen Sprachen. Sie k@nnen Werte, Kno-
ten oder Knotenb,ume speichern:
<xsl:variable name="alldata">
<xsl:if test="position()=last()">
TRUE
</xsl:if>
<xsl:if test="position()=1">
FALSE
</xsl:if>
</xsl:variable>
<xsl:call-template name="show.files">
<xsl:with-param name="handler">no</xsl:with-param>
</xsl:call-template>
<xsl:template name="show.files">
<xsl:param name="handler" select=""/>
...
XSLT im Alltag
Nummern XSLT verf:gt :ber einige komplexere Anweisungen, die f:r gr@-
ßere Projekte von Bedeutung sind. Dazu geh@rt <xsl:number> zum
Erzeugen fortlaufender Nummern oder Buchstabenfolgen.
Knoten kopieren Oft ist auch der Umgang mit ganzen Knoten notwendig, statt des
Textinhalts des Knotens. Dann findet <xsl:copy-of> Verwendung.
Sollen Knoten und Attribute kopiert werden, k@nnen mehrere An-
weisungen mit <xsl:copy> zusammengefasst werden.
Sandini Bib
Daten transformieren mit XSLT 485
<xsl:template match="*">
<xsl:copy>
<xsl:copy-of select="@*">
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
Da sich hier die Frage stellt, warum ein Dokument ausgerechnet Ausgabe-
mit XSLT unver,ndert kopiert werden sollte, ist ein Blick auf steuerung
<xsl:output> angebracht. Mit dieser Anweisung, die immer am
Anfang des Dokumentes steht, kann die Kodierung des Aus-
gabestromes gesteuert werden. Wenn Ihr XML-Dokument UTF-8
kodiert ist, k@nnen Sie es mit der Kopiervorlage des letzten Bei-
spiels leicht in ein anderes Format bringen, nebenbei auch ins
HTML 4.0-Format:
F:r gr@ßere Projekte k@nnen Sie XSLT-Dateien mit Hilfe der An-
weisungen <xsl:output> und <xsl:include> importieren. Mit Hilfe
von <xsl:include> kann ein Dokument so eingef:gt werden, als
w,re der Inhalt an dieser Stelle geschrieben worden. Der Import
hat eine geringere Priorit,t; stehen Regeln miteinander im Kon-
flikt, unterliegen die importierten.
XSLT-Funktionen
Da Transformationen oft in Abh,ngigkeit von konkreten Daten ab-
laufen, stellt XSLT einige elementare Funktionen zur Verf:gung,
die vor allem in select- und test-Attributen Anwendung finden.
End Class
Listing 5.11: XML lesen, transformieren und ausgeben (XsltNewsControl.ascx.vb)
Dann wird die XSLT-Datei, basierend auf der Auswertung der Ei-
genschaft Layout, geladen. Der korrekte physische Pfad wird mit
Server.MapPath ermittelt:
xTrans.Load (Server.MapPath É
(String.Format("data/{0}.xslt", Layout)) É
)
Die n,chsten beiden Zeilen holen die Daten aus dem Speicher
und laden sie als Zeichenkette in das Label-Steuerelement. Da der
Datenzeiger nach dem Schreibvorgang am Ende des Datenstro-
mes steht, muss er zuerst auf den Anfang – Position 0 – gesetzt
werden:
xWrite.Seek (0, SeekOrigin.Begin)
</xsl:template>
<xsl:template match="newscontent">
<hr noshade="noshade"/>
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="title">
<h3><xsl:value-of select="."/></h3>
</xsl:template>
<xsl:template match="text">
<div style="background-color:silver">
<xsl:value-of select="."/>
</div>
</xsl:template>
</xsl:stylesheet>
Listing 5.12: XSLT-Datei zur Darstellung der Nachrichten aus news.xml
(mainpage.xslt im Ordner data)
Ausgabe- Auf eine Erl,uterung soll hier verzichtet werden, da der Code kei-
formatierung nerlei Besonderheit enth,lt. Jedes Element wird entsprechend
dem Bedarf formatiert; die Ausgabe erfolgt als HTML. Der XSLT-
Prozessor wird die Ausgabe :brigens bei der Angabe von
method="html" konform zu HTML 4.0 formatieren. Aus der
XHTML-Darstellung <hr noshade="noshade"/> wird deshalb in der
Ausgabe <hr noshade>. M@chten Sie XHTML 1.0 erzeugen, schrei-
ben Sie in der XSLT-Datei folgende Formatierung:
xA.InnerText = "true"
Else
xA.InnerText = "false"
End If
xE1.Attributes.Append(xA)
xA = xDoc.CreateAttribute("system")
If fa = FileAttributes.System Then
xA.InnerText = "true"
Else
xA.InnerText = "false"
End If
xE1.Attributes.Append(xA)
xA = xDoc.CreateAttribute("readonly")
If fa = FileAttributes.ReadOnly Then
xA.InnerText = "true"
Else
xA.InnerText = "false"
End If
xE1.Attributes.Append(xA)
xE.AppendChild(xE1)
currentElement.AppendChild(xE)
Next
End If
Catch
xE = xDoc.CreateElement("error")
xE.InnerText = "Verzeichnis nicht gefunden"
currentElement.AppendChild(xE)
End Try
End Sub
xA = xDoc.CreateAttribute("path")
xA.InnerText = Server.MapPath(path)
xE.Attributes.Append(xA)
xDoc.AppendChild(xE)
ReadDir(Server.MapPath(path), xE)
xArgs.AddParam("showfile", "", file)
xArgs.AddParam("aspx", "", Request.Path)
xTrans.Transform(xDoc, xArgs, Response.Output)
End Sub
End Class
Listing 5.13: Dynamisches Erzeugen und Transformieren von XML mit Parametern
(XmlWriterFileList.aspx.vb)
Wie es Es kommt hier auf einige Details an, die ausf:hrlicher vorgestellt
funktioniert werden sollen. Als Basis dient die Klasse XmlDocument, die auf-
grund der Parameter f:r die Transform-Methode gew,hlt wurde.
Es kam in dem Beispiel darauf an, die Ausgabe an einen univer-
sellen TextWriter zu senden. Eine Klasse, die diese Klasse erbt, ist
Response.Output, der Ausgabepuffer f:r den Webserver. Damit
k@nnen die Daten ohne Umwege zum Browser gelangen. Die Me-
thoden zum Erzeugen der Elemente unterscheiden sich nat:rlich
vom letzten Beispiel.
Mit AppendChild wird dann ein neues Element jeweils an das gera-
de aktuelle angeh,ngt. Bei geschicktem Aufbau entsteht so der
XML-Baum. Der Ablauf gleicht sich im Programm immer wieder.
Erst wird ein neues Element erzeugt (xE ist vom Typ XmlElement):
xE = xDoc.CreateElement ("dirlist")
xA = xDoc.CreateAttribute ("path")
xA.InnerText = Server.MapPath(path)
Sandini Bib
Daten transformieren mit XSLT 495
xE.Attributes.Append (xA)
xDoc.AppendChild (xE)
<html>
<head>
<title>Verzeichnisliste</title>
<style>
ul b { background-color: #eeeeee; }
li { font-size: 10pt; }
</style>
</head>
<body>
<basefont face="Verdana"/>
<h1><xsl:value-of select="./@path"/></h1>
<xsl:apply-templates />
</body>
</html>
</xsl:template>
<xsl:template match="error">
<div style="color:red; font-weight:bold">
<xsl:value-of select="."/>
</div>
</xsl:template>
<xsl:template match="directory">
<ul><b><xsl:value-of select="./@name"/></b><br/>
<xsl:apply-templates/>
</ul>
</xsl:template>
<xsl:template match="file">
<li>
<xsl:element name="a">
<xsl:attribute name="href">
<xsl:value-of select="$aspx"/>?file=
<xsl:value-of select="name"/>
</xsl:attribute>
<xsl:value-of select="name"/>
</xsl:element>
<xsl:if test="$showfile=name">
<span style="border:1px blue solid">
<xsl:apply-templates É
select="size|attributes" />
</span>
</xsl:if>
</li>
</xsl:template>
<xsl:template match="attributes">
Attribute:
<xsl:choose>
<xsl:when test="@archive='true'">A</xsl:when>
<xsl:when test="@compressed='true'">C</xsl:when>
Sandini Bib
Daten transformieren mit XSLT 497
<xsl:when test="@hidden='true'">H</xsl:when>
<xsl:when test="@system='true'">S</xsl:when>
<xsl:when test="@readonly='true'">R</xsl:when>
</xsl:choose>
</xsl:template>
<xsl:template match="size">
Gr]ße: <xsl:value-of select="."/> Byte
</xsl:template>
</xsl:stylesheet>
Listing 5.14: Parametrisiertes XSLT-Programm (data/getfiles2.xslt)
Die Auswertung des Parameters findet mit Hilfe einer Auswertung des
<xsl:if>-Anweisung statt. F:r den Fall, dass der Name einer Datei Parameters
:bergeben wurde, wird beim Auftreten dieser Datei in der gesam-
ten XML-Datei die Ausgabe der zus,tzlichen Informationen (At-
tribute und Gr@ße) gesteuert:
<xsl:if test="$showfile=name">
Das ist :brigens nicht ganz perfekt, weil theoretisch Dateinamen Diskussion und
mehrfach auftreten k@nnen. Das Programm wurde aber ohnehin :bung
Zusammenfassung
Dieser Abschnitt zeigte, wie Sie XML direkt erzeugen, transfor-
mieren, mit Parametern die Transformation steuern und so den
notwendigen »Arbeitscode« auf ein Minimum reduzieren. Denn
die eigentliche Arbeit wird von der Transformation und dem
XML-Parser erledigt. Das Programm ist deshalb auch im Verh,lt-
nis zum erreichten Effekt sehr klein. Dies kann bei der Entwick-
lung gr@ßerer Applikationen vorteilhaft sein, weil die Fehlerquote
sinkt. Dar:berhinaus ist ein großer Teil der Funktionen auch dann
noch ,nderbar, wenn der Programmcode selbst nur als Assembly
vorliegt. Sie k@nnen so robuste und dennoch anpassbare Program-
me schreiben, ohne den Quellcode herausgeben zu m:ssen. Sie
k@nnen außerdem gegen:ber Kunden darauf verweisen, dass le-
diglich Kenntnisse in XML und XSLT notwendig sind, um die <n-
derungen selbst vorzunehmen. Beide Formate sind bekannt, nor-
miert und gut dokumentiert. Zu beiden gibt es viel Fachliteratur
und viele Seminare. Und beide sind letztlich einfacher zu beherr-
schen als ein vollst,ndig in VB.NET geschriebenes Programm.
Wenn Sie Bedarf an In-House-Schulungen zu diesen Themen ha-
ben, stehen Ihnen die Autoren gern zur Verf:gung.
Sandini Bib
B Praktische
Programmierung in
ASP.NET
Sandini Bib
Sandini Bib
6 Programmierung von
Web Forms
Die Schnittstelle zum Anwender wird durch das gebildet, was der
Browser anzeigt. Dies sind – im weitesten Sinne – so genannte
»Web Forms«. Dies ist ein Oberbegriff f:r eine gestaltungsorien-
tierte Softwareentwicklung, der an Win Forms aus der Windows-
Programmierung angelehnt ist. Letztlich dreht sich alles um die
Gestaltung der Benutzerschnittstelle und die Hinterlegung der be-
n@tigten Funktionalit,t.
6.1 Schnellstart
Dieser Abschnitt gibt einen kompakten 5berblick :ber das Thema
und zeigt sinnvolle Verkn:pfungen mit erg,nzenden und vor-
bereitenden Kapiteln. Der Wegweiser in die Referenz hilft, die
passenden Seiten in der MSDN-Online-Referenz besonders
schnell zu finden.
Wenn Sie mit Visual Studio .NET arbeiten, wird der bentigte Namens-
raum immer im Code eingebunden. HTML-Elemente, die Sie aus der
Toolbox im Designer hinzuf#gen, sind immer HTML bzw. Web Server-
Steuerelemente.
Ereignisse
Wie viele andere Objekte, kennen auch HTML Server-Steuerele- Ereignis-
mente Ereignisse, die auf Benutzeraktionen reagieren. Mit entspre- behandlung
chend benannten Ereignisbehandlungsmethoden k6nnen Sie diese
im Code abfangen. Der Name ist frei whlbar, solange er den Be-
dingungen der Namensvergabe f.r Methodennamen in der ge-
whlten Programmiersprache entspricht. Er wird im HTML-
Element selbst meist als Attribut onClick festgelegt (es gibt noch ei-
nige andere solche Attribute f.r Ereignisse, aber die Reaktion auf
einen Mausklick ist die hufigste). Beachten Sie, dass dieses Ver-
arbeitungsprinzip nichts am .blichen Ablauf zwischen Browser
Sandini Bib
506 6 Programmierung von Web Forms
Kompatibilitt zu HTML
Auch fr Netscape Der vollkommen auf HTML und HTTP aufbauende Verarbei-
tungszyklus der HTML Server-Steuerelemente f.hrt auch zu einer
sehr wichtigen Aussage: Alle Steuerelemente sind vollstndig
HTML-kompatibel und lassen sich mit allen Browsern darstellen.
Es handelt sich nicht um Nachfahren der ActiveX-Controls oder
hnlicher proprietrer Erweiterungen.
HTML-Tag Klassenname
<a> HtmlAnchor
<button> HtmlButton
HTML-Tag Klassenname
Alle sonstigen Tags, die allein HtmlControl
stehend auftreten, beispielsweise <br/>
<form> HtmlForm
Dient der Generierung neuer Elemente HtmlGenericControl
<img> HtmlImage
<input type="button"> HtmlInputButton
<input type="reset">
<input type="submit">
<input type="checkbox"> HtmlInputCheckBox
<input type="text"> HtmlInputControl
<input type="file">
<input type="submit">
<input type="file"> HtmlInputFile
<input type="hidden"> HtmlInputHidden
<input type="image"> HtmlInputImage
<input type="radio"> HtmlInputRadioButton
<input type="text"> HtmlInputText
<input type="password">
<select> HtmlSelect
<textarea> HtmlTextArea
<input type="checkbox"> HtmlCheckBox
<table> HtmlTable
<td> HtmlTableCell
<tr> HtmlTableRow
Mehrere Zellen einer Reihe HtmlTableCellCollection
Mehrere Reihen einer Tabelle HtmlTableRowCollection
<tr> HtmlTableRow
Alle sonstigen Tags, die als Container auftreten, HtmlContainerControl
beispielsweise <b>, <i> usw.
seite.aspx Seite.aspx.vb
<html> Imports ...
<head>
<title>Web Forms</title> Public Class Test
</head> Inherits Page
<body> Protected label1 As Label
<form runat="server"> Protected tb1 As TextBox Ihre Eingabe bitte:
<asp:Label runat="server" id="Label1"/> Protected label2 As Label
<br/>
<asp:TextBox runat="server" id="tb1"/> Public Sub Page_Load() _
<asp:Button runat="server" id="btn1" Handles Mybase.Load
onClick="Btn1_Click" Label1.Text = "Ihre Eingabe bitte:" Mustereingabe
Text="Absenden"/> End Sub
<asp:Label runat="server" id="Label2"/>
</body> Public Sub Btn1_Click(s As object, e As EventArgs)
</html> Dim Eingabe As string = TextBox.Text
Label2.Text = Eingabe
End Sub
End Class
Eine wichtige Eigenschaft ist Attributes. Dies ist eine Kollektion, Attribute-
da Elemente mehr als ein Attribut enthalten k6nnen. Das folgende Kollektion
<ul>
<li><a href="htmlcontrol.aspx?header=blue">
Blaue 9berschrift sehen</a></li>
<li><a href="htmlcontrol.aspx?header=red">
Rote 9berschrift sehen</a></li>
<li><a href="htmlcontrol.aspx?header=green">
Gr:ne 9berschrift sehen</a></li>
</ul>
</body>
</html>
Listing 6.1: Anwendung von HTML Server-Steuerelementen (HtmlControl.aspx)
Wie es Zum HTML Server-Steuerelement wird hier das Tag <h1> be-
funktioniert stimmt. Manipuliert wird das Attribut style, mit dem sich die Ge-
staltung .ber Cascading Style Sheets (CSS) bestimmen lsst. Die
Definition erfordert neben dem Attribut runat="server" auch die
Vergabe eines Namens .ber id:
Der Name des Objekts ist nun head1. Der Zugriff auf ein bestimm-
tes Attribut erfolgt .ber die bereits verwendete Schreibweise f.r
Kollektionen:
head1.Attributes("style") =
Abbildung 6.4: Nach dem Klick auf einen Link wechselt die Farbe der :berschrift.
<b><i></i></b>
In dieser Folge ist <i> dem Tag <b> untergeordnet. Da alle Objekte
innerhalb der Seite instanziiert werden, spielt das nicht zwingend
Sandini Bib
HTML Server-Steuerelemente (HTML Server Controls) 511
eine Rolle bei der Programmierung. Wenn Sie aber auf die Hierar-
chie R.cksicht neben m.ssen, gibt es einen Weg, die Anordnung
zu ermittelt. HtmlControl kennt dazu die Eigenschaft ControlCol
lection. Dies ist eine Kollektion der Objekte, die dem betreffenden
Objekt untergeordnet sind. Dies ist nur dann der Fall, wenn es
sich um Containerelemente handelt. Einfache Tags k6nnen in der
Kollektion zwar selbst enthalten sein, haben aber keine Kindele-
mente.
Neben dem Zugriff auf Tags kann auch jedes Attribut erreicht Attribute
werden. Da hufig CSS verwendet wird und das style-Attribut in
HTML wiederum viele Anweisungen enthalten kann, besteht zu-
stzlich eine M6glichkeit, auf jeden einzelnen Stylewert zuzu-
greifen. Beide, Attribute und Styles, bilden Kollektionen, wenn
mehrere Werte vorhanden sind.
Damit bei der Abfrage das Programm nicht hngen bleibt, wenn
ein Element ohne die erwarteten Kindelemente angetroffen wird,
ist noch die Methode HasControls von Bedeutung. Sie gibt True zu-
r.ck, wenn weitere Kindelemente existieren. Typisch f.r den Um-
gang mit Hierarchien sind rekursive Methoden. Diese rufen sich
selbst auf und k6nnen beliebig tiefe Verschachtelungen analysie-
ren. Das folgende Beispiel zeigt eine solche Anwendung:
<body>
<h1>Willkommen auf unserer Website</h1>
Viel Spaß mit unseren Angeboten:
<ul runat="server" type="disk">
<li runat="server" style="color:red">
Blaue 9berschrift sehen</li>
<li runat="server" type="square"
style="color:blue; font-weight:bold">
Rote <b runat="server">9berschrift</b> sehen</li>
<li runat="server">Gr:ne 9berschrift sehen</li>
</ul>
Servercontrols:<br/>
<pre><asp:label id="ausgabe" runat="server"/></pre>
</body>
Listing 6.2: Auslesen aller HTML Server-Steuerelemente einer Seite mit Attributen
(HtmlControlContainer.aspx)
Die eigentliche Arbeit wird in der Code-Datei und dort in der Me-
thode getControl erledigt:
Wie es Die Tags, die untersucht werden k6nnen, sind im HTML-Teil des
funktioniert Beispiels mit runat="Server" gekennzeichnet. Die Ausgabe der
Analyse erfolgt mit einem Web Server-Steuerelement:
wre ebenso m6glich. Dann folgt der Typ des Steuerelements, hier
Label. Als Letztes ist der Namen anzugeben, der exakt der Schreib-
weise im Attribut id entsprechen muss.
Die Definition erwartet, dass ein Wert vom Typ Control .bergeben
wird:
If c.HasControls() Then
Dim hc As System.Web.UI.HtmlControls.HtmlControl
Sandini Bib
514 6 Programmierung von Web Forms
hc ist nun tatschlich ein Objekt vom Typ HtmlControl, das auch si-
cher ein HTML Server-Steuerelement ist. Dieser Typ ist mit
HtmlGenericControl vollkommen kompatibel. Diese Objekte besit-
zen eine Reihe von Eigenschaften; die wichtigsten werden am En-
de des Abschnitts zusammengefasst. Zuerst wird der Name des
Tags ausgelesen und dem Anzeigeelement zugewiesen:
ausgabe.Text += ("<" + hc.TagName)
Nun werden alle Attribute anhand der Schl.ssel mit einer For
Each-Schleife durchlaufen. Hier wird direkt auf die Attribute zu-
gegriffen. Dies ist m6glich, da die Kollektion intern die Schnittstel-
le IEnumeration implementiert. Die Betrachtung der vielfltigen
M6glichkeiten von Kollektionen finden Sie in Abschnitt 4.3, »Auf-
zhlungen und Kollektionen« ab Seite 222.
ausgabe.Text += (" " + ss + "=""" + hc.Attributes(ss) + " \ """)
HasControls Der letzte Teil der Methode getControls dient dem rekursiven Auf-
ruf. Dazu wird wieder .berpr.ft, ob das Objekt weitere unterge-
ordnete Steuerelemente enthlt:
If c.HasControls() Then
Ist das der Fall, werden diese mit For Each durchlaufen und die
Methode f.r jedes Element aufgerufen. Durch die Rekursion wird
dieser Prozess beliebig tief fortgesetzt. Irgendwann ist HasControls
nicht mehr True. Dann luft die Methode zum Ende durch und
l6st die rekursiven Aufrufe wieder auf.
Sandini Bib
HTML Server-Steuerelemente (HTML Server Controls) 515
Wenn Sie derartige Zugriffe auf die HTML Server-Steuerelemente Methoden und
entwerfen, sollten Sie die wichtigsten Methoden und Eigenschaf- Eigenschaften
ten kennen. Die Tabellen am Ende des Abschnitts fassen diese zu-
sammen.
<body>
<h1>Willkommen auf unserer Website</h1>
<div style="background-color:#eeeee; font-family:Arial"
runat="Server" id="errormessage"/>
WFhlen Sie den den richtigen Link:<br/>
<ul>
<li><a href="HtmlControlContainerText.aspx?test=2">
Versuch 1</a></li>
<li><a href="HtmlControlContainerText.aspx?test=1">
Versuch 2</a></li>
<li><a href="HtmlControlContainerText.aspx?test=2">
Versuch 3</a></li>
</ul>
</body>
Listing 6.4: Anwendung von Container Controls (HtmlControlContainerText.aspx)
Sandini Bib
516 6 Programmierung von Web Forms
Auf das Objekt mit dem Namen errormessage kann nun außer mit
den bereits bei HtmlControl beschriebenen Eigenschaften auch mit
InnerText und InnerHtml zugegriffen werden. Damit ist die Mani-
pulation des eingeschlossenen Textes m6glich.
InnerText Die Eigenschaft InnerText schreibt den Text nicht nur in das Tag,
InnerHtml sondern maskiert auch die f.r HTML wichtigen Zeichen, »<«, »>«
und »&«; durch die Entitten «<«, »>« und »&« dar-
gestellt. Wenn HTML ausgegeben werden soll, ist deshalb
InnerHtml zu verwenden.
1 Die Tatsache, dass dieses Element geschlossen ist, sollte nicht dar.ber hin-
weg tuschen, dass <div> per Definition Text oder andere Elemente enthal-
ten darf und sich in der gezeigten Schreibweise wie ein leerer Container ver-
hlt, der freilich jederzeit gef.llt werden kann – genau das wird im Beispiel
auch gemacht.
Sandini Bib
HTML Server-Steuerelemente im Detail 517
Abbildung 6.6: Erzeugen von Text zur Laufzeit (Listing 6.4 und 6.5)
Wichtige Eigenschaften
Dieser Abschnitt zeigt die wichtigsten Eigenschaften und Metho-
den der HTML Server-Steuerelemente in tabellarischer Form.
Eigenschaft Bedeutung
Attributes Kollektion der Attribute
Style Kollektion der Style-Anweisungen des Attributes style
Controls Kollektion der untergeordneten Control-Objekte
TagName Name des Tags
Parent Zugriff auf das bergeordnete Control-Objekt
ID ID wie im Attribut id angegeben
ClientID Automatisch vergebene, interne ID
Eigenschaft Bedeutung
Visible Steuert die Sichtbarkeit, true = Sichtbar, false = Un-
sichtbar
Disabled Steuert, ob das Element aktiv ist. Dies ist nicht bei allen
Elementen anwendbar.
Wichtigen Methoden
Die wichtigsten Methoden der Steuerelemente zeigt die folgende
Tabelle:
Methode Bedeutung
ToString Umwandlung in eine Zeichenkette
RenderControl Schreibt das vernderte Element in ein Objekt vom
Typ HtmlTextWriter zur spteren Ausgabe
DataBind Bindet Datenbankinformationen an das Element
(nur f r Listenelemente und Tabellen interessant)
Steuerelemente Das Entfernen ist mit den Mitteln einer Kollektion m6glich. Alle
entfernen Steuerelemente einer Ebene sind in solchen Kollektionen vom Typ
LiteralControl
ControlCollection enthalten. Zum Entfernen wird die Methode
Remove verwendet, die ein Steuerelement als Argument erwartet,
bzw. RemoveAt, wo ein numerischer Index erforderlich ist. Wenn alle
Elemente entfernt werden sollen, kann Clear eingesetzt werden.
Der Index ist leicht zu ermitteln. In der Objekthierarchie tauchen
nur die Steuerelemente explizit auf, die Sie mit runat="server" ge-
kennzeichnet haben. Alles .brige wird als Objekt vom Typ Literal
Control verf.gbar gemacht. Wie das bei einem typischen HTML-
Quelltext aussieht, ist der folgenden Abbildung zu entnehmen.
Sandini Bib
HTML Server-Steuerelemente im Detail 519
Das Hinzuf.gen von Elementen ist ebenso m6glich, setzen Sie da- Hinzufgen
zu die Methode Add ein:
Dem Konstruktor wird dabei der Name des Elements als Zeichen-
kette .bergeben, in diesem Fall entsteht also ein <li>-Tag. Dieses
Tag ist ein Container und kann deshalb mit Text gef.llt werden:
Liste.Controls.Add(LiElement)
Die L6sung ist ebenso trickreich wie banal – es wird hier intern Ja- Das konventio-
vaScript verwendet. In der HTML-Programmierung ist dies ein nelle Verfahren
mycall()
{
document.form.action = "formularziel.aspx";
document.form.submit();
}
Der Klick auf den Link f.hrt so zum Senden des Formulars. Damit Wie ASP.NET
arbeitet auch ASP.NET. Der einzige Unterschied: Sie m.ssen Ja- JavaScript
verwendet
vaScript nicht kennen und brauchen auch keine Funktionen defi-
nieren. Um Hyperlinks in Formularen behandeln zu k6nnen, m.s-
sen Sie diese nur innerhalb der <form>-Tags platzieren und zum
Server-Steuerelement erklren. Das folgende Beispiel zeigt eine al-
ternative Form der Datenverarbeitung. Zuerst der HTML-Teil:
<body ms_positioning="gridlayout">
<h1>
shop
</h1>
unsere produkte:
<form runat="server" id="myform">
<ul>
<li>
<a runat="server" id="a0001"
onserverclick="check_click"></a>
Sandini Bib
522 6 Programmierung von Web Forms
<li>
<a runat="server" id="a0002"
onserverclick="check_click"></a>
<li>
<a runat="server" id="a0003"
onserverclick="check_click"></a>
</li>
</ul>
</form>
<div id="bestaetigung" runat="server"></div>
</body>
Listing 6.8: Reaktion auf Klickereignisse (AnchorState.aspx)
Das Programm basiert auf den mit runat="server" zu HTML Ser- Wie es
ver-Steuerelementen konvertierten <a>-Tags. Diese enthalten je- funktioniert
weils ein spezielles Attribut, onServerClick. Der Parameter be-
zeichnet eine Methode, mit der Sie auf das Klickereignis reagieren
m6chten:
Der Link ist vorerst leer, er wird im Beispiel erst zur Laufzeit mit
Daten gef.llt. Dazu ist ein Zugriff auf die Kollektion der HTML
Server-Steuerelemente erforderlich. Da es sich um ein Formular
handelt, interessieren hier nur die Steuerelemente, die im Formu-
lar sind:
Dim c As ControlCollection = myform.Controls
Den Index auf das Array bestimmt die Hilfsvariable k, die mit je-
der erfolgreichen Zuweisung um eins erh6ht wird:
k=k+1
Ereignisbe- Nun ist die Seite vollstndig und wird an den Browser gesendet.
handlung Jeder Klick auf einen Link f.hrt zum Aufruf der Methode
check_Click. Diese m.ssen Sie selbst definieren. Sie hat, wie alle
anderen Ereignisbehandlungsmethoden auch, die Parameter Sen-
derobjekt und Ereignisargument. Außerdem wird mit Handles de-
finiert, auf welche Ereignisse reagiert werden soll:
Die Variable sender enthlt in diesem Fall das Objekt des Steuer-
elements, welches das Ereignis ausgel6st hat. Es wird nun explizit
in ein HtmlAnchor konvertiert:
<body ms_positioning="gridlayout">
<h1>
Shop
</h1>
Unsere Produkte:
<form name="myform" method="post" action="AnchorState.aspx"
id="myform">
<input type="hidden" name="__EVENTTARGET" value="" />
<input type="hidden" name="__EVENTARGUMENT" value="" />
<input type="hidden" name="__VIEWSTATE"
value="dDwtMTYxODcyNzYxODt0PDtsPGk8MT47aTwzPjs+O2w8dDw7
bDxpPDE+O2k8Mz47aTw1Pjs+O2w8dDxwPGw8aW5uZXJodG1sOz47bD
xDb2Rlc2NocmVpYmVyIDEuMCAoNjI5OSw5MCk7Pj47Oz47dDxwPGw8
aW5uZXJodG1sOz47bDxEYXRlbmJhbmtlciAxLjEgKDk5LDkwKTs+Pjs7Pj
t0PHA8bDxpbm5lcmh0bWw7PjtsPFByb2pla3RvciAyLjAgKDM5LDAwKTs
+Pjs7Pjs+Pjt0PHA8bDxpbm5lcmh0bWw7PjtsPEFydGlrZWwgQ29kZXNja
HJlaWJlciAxLjAgKDYyOTksOTApIG1pdCBJRCBhMDAwMSB3dXJkZSBn
ZXcmYXVtbFw7aGx0Ljs+Pjs7Pjs+Pjs+DMGUCj6qjHZLNGuwz6QYGmTxkvQ=" />
<script language="javascript">
<!--
function __doPostBack(eventTarget, eventArgument) {
var theform = document.myform;
theform.__EVENTTARGET.value = eventTarget;
theform.__EVENTARGUMENT.value = eventArgument;
theform.submit();
}
Sandini Bib
526 6 Programmierung von Web Forms
// -->
</script>
<ul>
<li>
<a id="a0001" href="javascript:__doPostBack('a0001','')"> É
Codeschreiber 1.0 (6299,90)</a>
<li>
<a id="a0002" href="javascript:__doPostBack('a0002','')"> É
Datenbanker 1.1 (99,90)</a>
<li>
<a id="a0003" href="javascript:__doPostBack('a0003','')"> É
Projektor 2.0 (39,00)</a>
</li>
</ul>
</form>
<div id="bestaetigung">Artikel Codeschreiber 1.0 (6299,90) É
mit ID a0001 wurde gewählt.</div>
</body>
Zum einen finden Sie den Aufruf der JavaScript-Funktion, die im-
mer den Namen __doPostback trgt:
<a id="A0003" href="javascript:__doPostBack('A0003','')">
flchen zu. Die beiden Parameter der Funktion werden als event
Target und eventArgument bezeichnet. Die Mbertragung erfolgt, in-
dem die Werte an versteckte Felder .bergeben werden:
theform.__EVENTTARGET.value = eventTarget;
theform.__EVENTARGUMENT.value = eventArgument;
theform.submit();
Das Objekt vom Typ HtmlAnchor kann ein Ereignis onServerClick onServerChange
verarbeiten. Dies k6nnen Sie auch f.r <button> und <input onServerClick
E <input type="text">
E <input type="password">
E <input type="checkbox">
E <input type="radio">
E <input type="image">
E <input type="hidden">
E <textarea>
E <select>
Das Ereignis wird ausgel6st, wenn der Inhalt eines Feldes des vor-
hergehenden Formulars mit dem aktuellen Formular nicht .ber-
einstimmt. Auch die Methode, die onServerChange bedient, ist vom
Typ void und kann zwei Parameter vom Typ object und EventArgs
verarbeiten.
<input type="button"
style="font-weight:bold; font-size:24pt; color:green"/>
Attribut style Wenn Sie nun auf das Attribut style zugreifen, erhalten Sie eine
Zeichenkette, die m.hevoll zerlegt werden muss. Das erledigt
ASP.NET f.r Sie jedoch automatisch. Das folgende Beispiel zeigt,
wie eine Schaltflche einfach gestaltet werden kann:
<body>
<h1>Schaltfläche gestalten:</h1>
<form runat="server" >
<input type="button" id="btn" É
runat="server" onServerClick="Btn_Click"/>
</form>
<div id="Bestaetigung" runat="server"/>
</body>
Listing 6.10: Gestaltung einer Schaltf@che mit CSS (ButtonStyle.aspx)
End While
End Sub
End Class
Listing 6.11: Definition der Schaltfl@che und Klickbehandlungsmethode
(ButtonStyle.aspx.vb)
Die Aufzhlung wird mit einer While-Schleife durchlaufen, wobei Aufz-hlung durch-
bei jedem Durchlauf das nchste Element mit MoveNext ausgewhlt laufen
wird:
While keys.MoveNext()
Dann wird der aktuelle Inhalt des Elements mit Current ermittelt:
Nun wird dem Ausgabe-Tag der Name und der Wert des Style-
Attributes zugewiesen:
Damit wird dem Browser mitgeteilt, dass die sich die Art der
Mbertragung der Daten im K6rper der HTTP-Nachricht von der
eines normalen Formulars unterscheidet. Das ist notwendig, weil
die .bertragenen Dateien binre Daten enthalten k6nnen und die
normale Kodierung, wie sie bei Formulardaten verwendet wird,
nur unzureichenden Schutz bietet. Eine genaue Definition des
Vorgangs finden Sie in der RFC 1867, »Formularbasiertes Hoch-
laden von Dateien«.
kann der Inhalt nicht mit value vorausgef.llt oder per JavaScript
beeinflusst werden. Dies ist keine fehlenden Funktionen, sondern
Sicherheitsmaßnahmen. Eine Manipulation des Feldes k6nnte
nmlich .ber den waren Einsatz hinwegtuschen und eine ver-
deckte Vorauswahl k6nnte verwendet werden, um ohne weiteres
Zutun gezielt Dateien vom Computer des Benutzers zu beschaf-
fen. Da sich die Schaltflche nicht ndern lsst und es keinen Weg
gibt, daran vorbei das Feld zu f.llen – abgesehen von der direkten
Eingabe – ist das Verfahren relativ sicher.
Das bedeutet nat.rlich auch, dass der Erhalt des Inhalts mit dem
Anzeigestatus nicht funktionieren kann.
<h1>Dateien hochladen</h1>
<form id="HttpUploadFile" method="post" runat="server" É
enctype="multipart/form-data">
<input type="file" id="HttpUpload" runat="server"/>
<input type="submit" value="Jetzt :bertragen"/>
</form>
<asp:Label Runat="server" ID="FileResult"/>
<asp:DataGrid Runat="server" ID="FileList"/>
Listing 6.12: Formular zum Hochladen von Dateien (HttpUploadFile.aspx)
Wie es Dieses Programm hat mehrere Aufgaben. Zum einen soll gepr.ft
funktioniert werden, ob .berhaupt Daten .bertragen wurden. Wenn das der
Fall ist, sollen alle Dateien gr6ßer als 1 MByte abgelehnt werden.
Leider k6nnen Sie dies erst nach der Mbertragung pr.fen, die bei
Sandini Bib
HTML Server-Steuerelemente im Detail 533
ISDN einige Zeit in Anspruch nimmt. Lassen Sie sich hier nicht
von der Geschwindigkeit auf einem Entwicklungssystem tu-
schen.
If pf.ContentLength > 0
Dieses Beispiel ermittelt Breite und H6he eines Bildes. Mit der ge-
samten GDI+-Bibliothek kann nun die Verarbeitung der Daten er-
folgen.
HTML kennt per se keine Datentypen. Das f.hrt dazu, dass Attri- Datentypen
bute bei HTML Server-Steuerelementen immer als Zeichenkette
betrachtet werden. Tatschlich sind aber bestimmte Attribute
durchaus an bestimmte Datentypen bindbar, wie beispielsweise
die Breite einer Tabellenzelle (width="43", Typ Unit). Hier sind ent-
weder ganze Zahlen oder Prozentwerte erlaubt, aber mit Sicher-
heit nie eine Zeichenkette. Web Server-Steuerelemente besitzen
f.r alle in HTML zulssigen Attribute einzelne Eigenschaften. In-
sofern ist die Programmierung damit strenger am Klassen- und
Typkonzept des NET-Frameworks ausgerichtet. Von Vorteil ist
auch die Verf.gbarkeit komplexer Objekte, wie ganzer Kalender,
die intern aus Tabellen und Links bestehen.
Bei den HTML Server-Steuerelementen wurde gezeigt, dass Stan- Browser-
dard-HTML-Tags erzeugt werden. Das funktioniert bei den Erkennung
Diese Syntax stammt aus der XML-Welt. Der konkrete Name setzt
sich aus dem XML-Namensraum »asp« und dem Namen der
Klasse »label« zusammen. Wie schon bei den HTML Server-Steu-
erelementen wird das Objekt dann im Programmteil bereitgestellt,
wenn es mit dem Attribut runat="server" versehen wurde.
Der Zugriff auf die Feldwerte erfolgt bei Textfeldern .ber die Ei- Textfelder
genschaft Text. Listen, also DropDownList oder ListBox, werden .ber
die Listenmitglieder angesprochen. Der erste in der Liste aus-
gewhlte Index wird in der Eigenschaft SelectedIndex .bergeben,
das Listenobjekt selbst in SelectedItem. Bei Kontrollkstchen
(CheckBox) und Optionsfeldern (RadioButton) ist die Eigenschaft
Checked gleich True, wenn das Element ausgewhlt wurde.
<html lang="de">
<head>
<title>RadioButton</title>
</head>
<body>
<h1>Was ist die beste Programmierumgebung É
für Webserver?</h1>
<form runat="server" >
<asp:radiobutton autopostback="true" É
OnCheckedChanged="Btn_Click" É
Sandini Bib
542 6 Programmierung von Web Forms
Wahl4.CheckedChanged, _
Wahl5.CheckedChanged
Dim currentRadio As RadioButton = CType(sender,
RadioButton)
Bestaetigung.Text = currentRadio.Text
End Sub
End Class
Listing 6.15: Code-Datei zur Behandlung des Autopostback-Ereignisses (AutoPost-
Back.aspx.vb)
Zur Besttigung des Vorgangs soll auf die Eigenschaft Text zuge-
griffen werden:
Bestaetigung.Text = currentRadio.Text
Hier kommt ein Steuerelement vom Typ Label zum Einsatz, dass
als HTML zu <span> mutiert. Ein Blick auf den HTML-Code ist an
dieser Stelle ohnehin spannender. Zuerst aber das Bild der fer-
tigen Seite:
Der Ausl6ser f.r das Absenden des Formulars ist der Aufruf einer
JavaScript-Funktion beim Auftreten des Mausereignisses onClick.
Dies f.hrt zu folgendem Eingabefeld:
E Panel
Dies ist ein Container, der eine definierte Flche belegt und
mit statischem Inhalt oder weiteren Elementen gef.llt werden
kann. Das korrespondierende HTML-Element ist <div>. Panel-
Steuerelemente erzeugen immer Abstze.
Sandini Bib
Web Server-Steuerelemente (Web Server Controls) 545
E Label
Dies ist ein Container, der mehrere Zeichen umfasst und ent-
weder allein im Fließtext oder als Kind eines Panel-Steuerele-
ments auftritt.
E PlaceHolder
Diese Klasse wird direkt von Control abgeleitet, nicht von
WebControl, wie die anderen. Die Objekte sind etwas primitiver
und haben weniger Methoden und Eigenschaften. Das Place
Holder-Steuerelement dient der Einbettung anderer Controls
oder der direkten Ausgabe von Text. Es erzeugt kein eigenes
HTML-Tag. Nat.rlich fehlen mangels umschließendem Tag
smtliche Formatierungsm6glichkeiten. Enthaltene Steuerele-
mente k6nnen wiederum alles enthalten, was mit Web Server-
Steuerelementen m6glich ist.
E Literal
Auch dieses Steuerelement erzeugt kein HTML selbst, sondern
dient der Ausgabe von einfachem Text. Auch hier sind keine
Formatierungsm6glichkeiten gegeben.
Das folgende Beispiel zeigt die Anwendung der Panel- und Label-
Steuerelemente. Zu Label finden Sie außerdem unzhlige Verwen-
dungen in den Beispielen dieses Buches.
<html>
<head>
<title>Panele und Label</title>
<style>
#PanelLabel {font-size:12pt; color:red; font-weight:bold}
</style>
</head>
<body>
<h3>Panele und Label</h3>
<form runat=server>
<asp:panel id="GroupPanel" runat="server"
BackColor="#eeeeee"
Height="50px" Width="250px">
<b>Einige Label:</b><br/>
</asp:panel>
<p>
<asp:checkbox id="CheckVisibility"
Text="Panel verstecken"
autopostback="true"
onCheckedChanged="checkVisibility"
runat="server"/>
<p/>
Sandini Bib
546 6 Programmierung von Web Forms
</form>
</body>
</html>
Listing 6.16: Erzeugen eines Panels und Einbau von Text (PanelLabel.aspx)
GroupPanel.Controls.Add(TextLit)
Was genau passiert, verrt ein Blick in den HTML-Code, den die-
ses Programm erzeugt:
<div id="GroupPanel" É
style="background-color:#EEEEEE;É
height:50px;É
width:250px;">
<b>Einige Label:</b><br/>
<span id="PanelLabel">Dieser Text ist ein Label</span>
<hr/>
</div>
Ohne das dies nochmals erlutert werden soll, enthlt auch dieses
Beispiel eine Anwendung der AutoPostBack-Funktion, die in die-
sem Fall das Panel-Objekt ein- und ausschaltet. Dies erfolgt mit
der Eigenschaft Visible.
Sandini Bib
548 6 Programmierung von Web Forms
Wenn ein Element unsichtbar gemacht wird, erledigt dies das Style-
Attribut display:none. Nichtsdestotrotz bleibt der HTML-Code im
Quelltext der Seite erhalten und ist f#r neugierige Benutzer sichtbar.
Zum Verstecken von Informationen ist dieser Weg nicht geeignet.
Das TextBox-Steuerelement
Texteingabefelder Damit ist nun Schluss, denn das Web Server-Steuerelement TextBox
definiert alle Arten von Eingabefeldern. Dank CSS erfolgt dies
auch mit einheitlichem Aussehen bei vergleichbaren Attributen.
Bei HTML allein ist das nicht der Fall, denn die Angabe size="10"
im Tag <input type="text"> f.hrt nicht zu derselben Breite des Fel-
des wie die Angabe columns="10" im Tag <textarea>, was man ei-
gentlich erwarten k6nnte.
<html>
<head>
<title>Textbox</title>
</head>
<body>
<h3>Textbox</h3>
<form runat=server>
<asp:radiobutton id="Zeile1" É
groupname="Zeilen" runat="server" É
autopostback="true" onCheckedChanged="setBox"
text="1 Zeile" value="1" /><br/>
<asp:radiobutton id="Zeile3" É
groupname="Zeilen" runat="server" É
autopostback="true" onCheckedChanged="setBox" É
Sandini Bib
Web Server-Steuerelemente (Web Server Controls) 549
Probleme mit Dann wird – ganz konventionell – mit der Form-Kollektion gear-
RadioButton beitet. Die Technik der Web Server-Steuerelemente beruht jedoch
eigentlich darauf, mit den vorhandenen Eigenschaften zu arbei-
ten. Optionsfelder sollen danach .ber ihre ID verarbeitet werden.
Wenn Sie aber direkt Werte verarbeiten m6chten, sollte eigentlich
das Attribut value benutzt werden. Erstaunlicherweise gibt es in
der Klasse RadioButton dazu keine passende Eigenschaft. Hier
wird zur Abwechslung und zur L6sung des »value«-Problems
mal direkt auf die Form-Daten zugegriffen, mit dem »alten«
Request.Form:
TextBox- Jetzt wird die TextBox entsprechend der Angabe eingerichtet. Dies
Eigenschaften erfolgt .ber die Eigenschaft TextMode. Zulssig sind drei Eigen-
schaften, die aus einer Aufzhlung vom Typ TextBoxMode entnom-
men werden k6nnen:
E TextBoxMode.MultiLine
Mehrzeiliges Feld, erzeugt <textarea>.
E TextBoxMode.SingleLine
Einzeiliges Feld, erzeugt immer <input type="text">.
E TextBoxMode.Password
Einzeiliges Feld, erzeugt immer <input type="password">.
Allein mit der Angabe der Zeilenanzahl ndert sich die Darstel-
lung nicht. Wenn die Zeilenzahl gr6ßer als 1 ist, wird der Modus
gendert:
TextEingabe.TextMode = TextBoxMode.MultiLine
TextEingabe.Rows = z
Was jetzt noch fehlt, ist eine M6glichkeit, das Formular zu senden.
Dazu werden Schaltflchen ben6tigt.
E CommandName
Hiermit teilen Sie dem Kommando einen willk.rlichen Namen
zu. Innerhalb der Ereignisbehandlungsmethode steht dieser
Name als Eigenschaft CommandName des Ereignisarguments vom
Typ CommandEventArgs zur Verf.gung.
E CommandArgument
Hiermit teilen Sie dem Kommando ein zustzliches Argument
zu. Innerhalb der Ereignisbehandlungsmethode steht dieser
Name als Eigenschaft CommandArgument des Ereignisarguments
vom Typ CommandEventArgs zur Verf.gung. Es steht Ihnen beim
Entwurf der Ereignisstruktur frei, dies zu verwenden und da-
mit die Kommandos weiter zu strukturieren.
<html lang="de">
<head>
<title>Buttons</title>
</head>
<body>
<h3>Ihre Bewertung bitte:</h3>
<form runat="server">
Sandini Bib
Web Server-Steuerelemente (Web Server Controls) 553
Die Variable e enthlt nun die Kommandos, die mit den Eigen-
schaften CommandName und CommandArgument abgefragt werden k6n-
nen:
Die Kommandos m.ssen nat.rlich nicht verwendet werden, wenn Beschriftung der
es nur eine einfache Sendeschaltflche gibt. Das Formular gelangt Schaltfl-che
dann auf dem normalen Weg zum Server, wo mit IsPostBack
festgestellt werden kann, ob die Seite das erste Mal oder nachfol-
gend aufgerufen wurde. Wollen Sie die Sendeschaltflche im Pro-
gramm gestalten, ist es dennoch notwendig, sie als Steuerelement
zu deklarieren. Das folgende Beispiel zeigt, wie die Beschriftung in
Abhngigkeit von der Situation gendert werden kann.
<html lang="de">
<head>
<title>Sendeschaltfläche</title>
</head>
<body>
<h1>Sendeschaltfläche</h1>
<form runat="server">
<asp:button id="senden" runat="server"/>
</form>
</body>
</html>
Listing 6.22: Beschriftung der Sendeschaltfl@che dynamisch @ndern (ButtonSubmit.aspx)
Nach dem das Senden der Formulare mit den gezeigten Metho-
den m6glich ist, sollte auch die Qualitt des Inhalts gepr.ft wer-
den. Eine spezielle Gruppe von Web Server-Steuerelementen ist
daf.r geeignet – die Kontroll-Steuerelemente (Validation Con-
trols). Beschrieben werden sie in Abschnitt 6.7, »Kontroll-Steuer-
elemente (Validation Controls)« ab Seite 616.
Sandini Bib
556 6 Programmierung von Web Forms
6.5 Listen-Steuerelemente
Zur Anzeige von Auswahlm6glichkeiten sind Listen besonders
geeignet. In ASP.NET ist es m6glich, nicht nur einfache Drop-
Down-Listen zu erzeugen, sondern auch die Standardfelder Opti-
onsfeld und Kontrollkstchen zu Listen zusammenzufassen. Da-
bei wird auch hier lediglich HTML erzeugt, whrend aus Sicht
des Programmierers nur ein Objekt existiert.
Einfache Listboxen
Listen Bei den Listen gibt es in HTML nur ein Tag, das von zwei Web
Server-Steuerelementen erzeugt wird:
E DropDownList
Dies sind Listen, die immer einzeilig erscheinen und beim An-
klicken herunter klappen (engl. drop down, daher der Name).
Sie werden in HTML mit <select size="1"> erzeugt.
Sandini Bib
Listen-Steuerelemente 557
E ListBox
Hier werden alle Elemente der Liste gleichzeitig angezeigt. Es
k6nnen ein oder auch mehrere Elemente ausgewhlt werden.
In HTML wird dazu ebenso <select> verwendet, mit dem At-
tribut size und einem Parameter gr6ßer als 1. Die Mehrfach-
auswahl kann mit dem Attribut multiple gestattet werden.
Die Elemente der Listen lassen sich .ber eigene Steuerelemente Listenelemente
erzeugen und ndern, ListItem genannt. Die Darstellung erfolgt
als <option>-Tag, das in HTML nur innerhalb einer Liste vorkom-
men darf. ASP.NET bringt bei Listboxen deutliche Fortschritte ge-
gen.ber der herk6mmlichen Programmierung. So war es nicht
einfach, den Zustand der Liste, also den Status der gewhlten Ele-
mente, zu erhalten. Mit Web Server-Steuerelementen ist dies kein
Problem mehr. Das folgende Beispiel zeigt, wie die Elemente einer
Listbox aus einem Array erzeugt werden k6nnen:
<html lang="de">
<head>
<title>Select</title>
</head>
<body>
<h1>Wählen Sie die Versandart</h1>
<form runat="server">
<asp:button id="auswahl" runat="server" É
text="Bitte wFhlen"/>
<asp:dropdownlist id="versand" runat="server"/>
</form>
</body>
</html>
Listing 6.24: Listbox dynamisch f>llen (SelectDropDownList.aspx)
Else
Dim versandarten() As String = {"Express-Paket", É
"Over-Night", É
"Standard 48 Stunden"}
Dim i As Integer = 0
Dim versandart As String
For Each versandart In versandarten
Dim versandoption As ListItem = New ListItem()
versandoption.Text = versandart
i = i + 1
versandoption.Value = i.ToString()
versand.Items.Add(versandoption)
Next
End If
End Sub
End Class
Listing 6.25: Code zu SelectDropDownList.aspx
(Ausschnitt aus SelectDropDownList.aspx.vb)
Beim Aufruf der Seite wird ein Array erzeugt, dass die Eintrge
enthlt. Dieses Array wird in einer Schleife durchlaufen:
F.r jedes Element wird nun ein Objekt vom Typ ListItem erzeugt:
versandoption.Value = i.ToString()
versand.Items.Add(versandoption)
Sandini Bib
Listen-Steuerelemente 559
Die Eigenschaft Items spielt beim Umgang mit Listen eine heraus- ListItemCollection
ragende Rolle. Objekte, die hier enthalten sind, sind vom Typ
ListItemCollection. Auch diese Klasse ist Bestandteil des Namens-
raumes System.Web.UI.WebControl. Da Elemente der Kollektion
nicht allein existieren k6nnen, sondern nur als Bestandteil von
Items, waren sie in der Mbersicht am Anfang des Kapitels nicht
enthalten. Wichtige Eigenschaften sind:
E Capacity
Gibt die maximale Anzahl Elemente an, die erlaubt sind.
E Count
Die aktuelle Anzahl der Elemente.
E Item
Zugriff auf ein Element. Außerdem ist dies die Standard-
methode, sodass der Zugriff mit der Schreibweise MeineListe
("ListElement") erfolgen kann.
Die Methoden entsprechen denen anderer Listen. Add f.gt ein Ele-
ment am Ende der Liste hinzu, Insert dagegen an einer bestimm-
ten Position. Clear l6scht alle Elemente, Remove dagegen nur ein be-
stimmtes. Interessant sind zwei spezielle Methoden dieser
Listenart: FindByText sucht ein Element mit einem bestimmten In-
halt der Eigenschaft Text; FindByValue entsprechend f.r Value.
Sandini Bib
560 6 Programmierung von Web Forms
<html lang="de">
<head>
<title>Select</title>
</head>
<body>
<h1>Wählen Sie die Versandart</h1>
<form runat="server">
<asp:button id="auswahl" runat="server" É
text="Bitte wFhlen"/>
<asp:radiobuttonlist id="versand" runat="server"/>
</form>
</body>
</html>
Listing 6.26: Dynamisch erzeugte Gruppe von Optionsfeldern (RadioButtonList.aspx)
ByVal e As System.EventArgs) _
Handles MyBase.Load
If IsPostBack Then
If versand.SelectedIndex = -1 Then
auswahl.Text = "Keine Auswahl"
Else
auswahl.Text = versand.SelectedItem.Text.ToString() É
+ " OK?"
End If
Else
Dim versandarten() As String = {"Express-Paket", É
"Over-Night", É
"Standard 48 Stunden"}
Dim i As Integer = 0
Dim versandart As String
For Each versandart In versandarten
Dim versandoption As ListItem = New ListItem()
versandoption.Text = versandart
i = i + 1
versandoption.Value = i.ToString()
versand.Items.Add(versandoption)
Next
End If
End Sub
End Class
Listing 6.27: Code zu RadioButtonList.aspx (Ausschnitt aus RadioButtonList.aspx.vb)
</tr><tr>
<td><input id="versand_1" type="radio" name="versand"
value="1" />
<label for="versand_1">Over-Night</label></td>
</tr><tr>
<td><input id="versand_2" type="radio" name="versand"
value="2" />
<label for="versand_2">Standard 48 Stunden</label></td>
</tr>
</table>
</form>
Formatierung von Interessant ist, dass eine Tabelle zur Formatierung eingesetzt
Listen wird. Tatschlich sind die Formatieroptionen, die sich daraus ab-
leiten lassen, sehr umfangreich. Wenn Sie sehr viele Elemente ha-
ben, wie es beispielsweise bei Umfrageseiten der Fall ist, helfen
diese Optionen enorm. Hervorzuheben sind folgende Eigenschaf-
ten:
E RepeatColumns
Anzahl der Spalten, in denen die Anzeige gruppiert wird.
E RepeatDirection
Richtung, in der gruppiert wird. Die beiden Tabellen zeigen
die Folge der Zellen.
E RepeatLayout
Diese Eigenschaft bestimmt die Art der Darstellung. Zulssig
sind folgende Werte der Aufzhlung RepeatLayout:
E RepeatLayout.Table
Die Darstellung erfolgt als Tabelle. Die ist der Standard-
wert.
E RepeatLayout.Flow
Die Darstellung erfolgt ohne Tabellenstruktur, also flie-
ßend.
<html lang="de">
<head>
<title>Shop</title>
</head>
<body>
<h1> Shop </h1>
Unsere Produkte:
<form runat="server">
<asp:checkboxlist id="produkte" runat="server"/>
<asp:button id="bestellen" runat="server"
text="Jetzt Bestellen"/>
</form>
</body>
</html>
Listing 6.28: Mehrfachauswahl mit Kontrollk@stchen (CheckBoxesMultiple.aspx)
Wie es Im Programm hat sich gegen.ber den letzten Beispielen nur we-
funktioniert nig gendert. Als Tag kommt nun CheckBoxList zum Einsatz:
Auch hier zeigt ein Blick in den HTML-Code, dass ASP.NET sehr
konventionell vorgeht und <input type="checkbox">-Tags in einer
Tabelle platziert. Die Repeater-Eigenschaften stehen auch hier zur
Verf.gung, falls gr6ßere Datenmengen anfallen.
6.6 Vorlagengebundene
Daten-Steuerelemente
In der Gruppe der Web Server-Steuerelemente gibt es drei Klas-
sen, die komplexere Elemente realisieren. Sie k6nnen damit gr6ße-
re Datenmengen komfortabel ausgeben. Ebenso wie bei den be-
reits vorgestellten Listen-Steuerelementen ist eine Bindung an
eine Datenquelle m6glich. Zustzlich kann jedoch die Steuerung
in einer f.r Listen typischen Weise erfolgen. Die verf.gbaren
Steuerelemente sind:
E <asp:repeater>
E <asp:datalist>
E <asp:datagrid>
Repeater
Einsatz Das Steuerelement Repeater ist das einfachste und universellste Ele-
ment. Es basiert wie alle Daten-Steuerelemente auf Vorlagen. Inner-
halb des Elementes k6nnen mehrere Bereiche definiert werden, die
sowohl die Gestaltung als auch den Inhalt beeinflussen. Dies hat ei-
nen signifikanten Vorteil gegen.ber der reinen programmtech-
nischen Steuerung der Ausgabe. Denn wenn Design und Code pa-
rallel entwickelt werden, ist eine solche Trennung optimal.
Eigenschaften Das Repeater-Steuerelement verf.gt .ber einige grundlegende Ei-
genschaften, anhand derer Sie den sinnvollen Einsatz abwgen
k6nnen:
Sandini Bib
Vorlagengebundene Daten-Steuerelemente 567
DataList
Das DataList-Steuerelement basiert wie alle Daten-Steuerelement Einsatz
auf Vorlagen. Innerhalb des Elementes k6nnen mehrere Bereiche
definiert werden, die sowohl die Gestaltung als auch den Inhalt
beeinflussen. Dies hat einen signifikanten Vorteil gegen.ber der
Sandini Bib
568 6 Programmierung von Web Forms
DataGrid
Einsatz Das DataGrid-Steuerelement basiert wie alle Daten-Steuerelement
auf Vorlagen. Innerhalb des Elementes k6nnen mehrere Bereiche
definiert werden, die sowohl die Gestaltung als auch den Inhalt
Sandini Bib
Vorlagengebundene Daten-Steuerelemente 569
E <HeaderTemplate>
Dieses Element wird nur einmal am Beginn der Liste ausgege-
ben. Hier kann die Gestaltung des Kopfbereiches erfolgen oder
ein 6ffnendes HTML-Tag wie <ul>, oder <table> stehen. Die
Angabe ist nicht zwingend. Eine Datenbindung an dieses Ele-
ment ist nicht m6glich, weil es nicht f.r die Ausgabe wieder-
holender Werte gedacht ist.
E <FooterTemplate>
Der Fußbereich wird mit dieser Vorlage erzeugt. Die Angabe
ist freiwillig. Wenn Sie bereits den Kopfbereich definiert ha-
ben, sollten Sie den Fußbereich unbedingt ebenfalls verwen-
den, weil Sie so sicherstellen k6nnen, dass die schließenden
HTML-Tags an der richtigen Stelle erscheinen (</ul> bzw.
</table> usw.). Auch dieses Element kann keine Daten binden.
E <ItemTemplate>
In dieser Vorlage k6nnen Sie Datenbindungsausdr.cke ver-
wenden. Das Steuerelement sorgt dann daf.r, dass diese wie-
derholt werden. Hier sollten Sie HTML so platzieren, dass es
zwischen die Kopf- und Fußzeilen passt.
Sandini Bib
Vorlagengebundene Daten-Steuerelemente 571
E <AlternatingItemTemplate>
Wenn dieses Element angegeben wird, erscheint es abwech-
selnd zu den zuvor definierten ItemTemplate-Vorlagen.
E <SeparatorTemplate>
Diese Element dient der Definition von Trennzeilen zwischen
den Elementen einer Auflistung.
F.r die hier behandelten Steuerelemente wird als Container der Da-
ten immer der Ausdruck Container.DataItem verwendet. Zur Aus-
wertung des aktuellen Inhalts des Containers kann zustzlich die
statische Methode Eval der Klasse DataBind verwendet werden. Eval
ist dann angebracht, wenn Formatierungen oder Konvertierungen
notwendig sind. VB.NET erledigt dies in den meisten fllen impli-
zit, sodass die relativ langsame Methode nur dann benutzt werden
sollte, wenn die Darstellung auf anderem Wege nicht gelingt. Der
Ausdruck w.rde dann folgendermaßen aussehen:
<%# DataBinder.Eval (Container.DataItem, "Datenquelle") %>
Was als Datenquelle angegeben wird, hngt davon ab, wie die Da-
ten strukturiert sind. Handelt es sich um Daten aus einer SQL-
Datenbank, werden meist Spaltennamen verwendet. Werden
Objekte verwendet, sollten diese .ber eine lesbare Eigenschaft
verf.gen, deren Namen angegeben wird. Das folgende Beispiel
demonstriert dies.
Wenn die Daten so gestaltet sind, das die Auswahl einer Daten-
quelle nicht erforderlich bzw. nicht m6glich ist, nutzen Sie folgen-
de Syntax:
<%# Container.DataItem %>
Abgesehen davon sind Sie in der Gestaltung des Ausdrucks frei. Formatierung der
Sie k6nnen beliebigen Code verwenden, eigene oder eingebaute Ausgabe
Sandini Bib
572 6 Programmierung von Web Forms
Zugriff auf eigene Generell k6nnen sehr viele verschiedene Datenquellen verwendet
Aufz-hlungs- werden. Letztlich ist allein das Vorhandensein einer Implementie-
klassen
rung von GetEnumerator ausreichend. Wenn Sie nun selbst Daten-
quellen bereitstellen, die nicht den bereits gezeigten »Standard-
typen« entsprechen, muss der Abruf in der Vorlage eine korrekte
Typumwandlung vornehmen. Das folgende Beispiel zeigt, wie Ei-
genschaften einer eigenen Klasse verwendet werden k6nnen:
<%#
CType(Container.DataItem.Eigenschaft, NameSpace.MeineKlasse)
%>
Zuerst wird auf den Container, dann auf das aktuelle Element
DataItem und – optional – eine seiner Eigenschaften zugegriffen.
Dann wird das Element in den urspr.nglichen Datentyp gewan-
delt. Sie m.ssen dazu den vollstndigen Namensraumverweis an-
wenden, wenn nicht mit der Direktive @Imports gearbeitet wird.
Danach stehen die Eigenschaften und Methoden des Objekts zur
Verf.gung.
Die Datenquelle muss eine Auflistung sein. Dies erfordert die Ab-
leitung von der Schnittstelle IEnumerable. Dazu geh6ren beispiels-
weise:
E ArrayList
E DataView
E Hashtable
E Verschiedene spezialisierte Kollektionen, wie CaptureCollection,
MatchCollection, StringCollection usw.
E Queue
E SortedList
aList.Add(9.5)
aList.Add(24.9)
SimpleList.DataSource = aList
SimpleList.DataBind()
End Sub
End Class
Listing 6.31: F>llen der Liste mit Daten (Ausschnitt aus SimpleRepeater.aspx.vb)
Wie es Die Definition der ArrayList erfolgt wie .blich. Da ArrayList unter
funktioniert anderem die Schnittstelle IEnumerable implementiert, kann das da-
raus abgeleitete Objekt aList direkt als Datenquelle verwendet
werden. Mit der Bindung durch die Methode DataBind erscheinen
die Daten auf der Seite.
Class SimpleRepeater2
Inherits System.Web.UI.Page
Private Structure Artikel
Dim _name As String
Dim _preis As Double
Dim _menge As Integer
Public Sub New(ByVal Name As String, É
ByVal Preis As Double, É
ByVal Menge As Integer)
Sandini Bib
Vorlagengebundene Daten-Steuerelemente 575
_name = Name
_preis = Preis
_menge = Menge
End Sub
ReadOnly Property Name() As String
Get
Return _name
End Get
End Property
ReadOnly Property Preis() As Double
Get
Return _preis
End Get
End Property
ReadOnly Property Menge() As Integer
Get
Return _menge
End Get
End Property
End Structure
End Class
Listing 6.32: Struktur zur Speicherung von Objekten
(Ausschnitt aus SimpleRepeater2.aspx.vb)
Sie k6nnen dann daraus abgeleitete Objekte in einer Liste spei- Datenbindung bei
chern und die einzelnen Eigenschaften der Struktur gezielt aus- der Zuweisung
geben. Das Speichern in der Liste erfolgt wie bereits zuvor f.r ska-
lare Werte gezeigt:
Das folgende Beispiel durchsucht ein Verzeichnis und listet alle IComparer
enthaltenen Dateien mit Hilfe des Repeater-Steuerelementes auf. IEnumerable
Werfen Sie zuerst einen Blick auf die Klasse, die die Repeater-
Steuerelemente mit den entsprechenden Werten f.llt:
Wie es Die Klasse besteht praktisch nur aus der Methode Page_Load. Dort
funktioniert sind zwei Variablen von Bedeutung. fi vom Typ FileInfo enthlt
die jeweils aktuellen Dateiinformationen, die dann in einem Ob-
jekt der Klasse fc – Typ FileCollection – gespeichert werden. Die
Objekte selbst entstammen einer weiteren Klasse, FileObject.
fi = New FileInfo(filename)
fc.AddFile(f)
filelist1.DataSource = fc
filelist1.DataBind()
Die Methode AddFile f.gt der Kollektion, die intern als Array defi-
niert ist, ein weiteres Element hinzu. Dazu wird die Gr6ße des Ar-
rays jeweils um ein Element erh6ht. Das Verfahren dient nur der
Demonstration (und erleichtert die Nutzung des Debuggers). In
einer »echten« Implementierung ist es sinnvoller, immer mehrere
leere Arrayelemente anzuf.gen und dann nur in gr6ßeren Schrit-
ten den Umkopiervorgang zu starten, der sich auf folgende Zeile
beschrnkt:
Array.Copy(_files, 0, _Newfiles, 0, _length)
Das private Feld _length enthlt die aktuelle Gr6ße der Liste.
Sandini Bib
582 6 Programmierung von Web Forms
Return _down
End If
If _a.FileSize < _b.FileSize Then
Return _up
End If
Return 0
End Function
End Class
Listing 6.39: Die Implementierung der Schnittstelle IComparer f>r individuelle Sortier-
funktionen (Ausschnitt aus FileCollectionClass.vb)
Die Besonderheit besteht hier in zwei Funktionen. Zum einen soll Wie es
nach der Dateigr6ße sortiert werden, was standardmßig nicht funktioniert
m6glich ist. Zum anderen soll die Sortierrichtung – auf- oder ab-
steigend – frei gewhlt werden k6nnen. Damit dennoch nur eine
Kodierung notwendig ist, wird der Sortierklasse im Konstruktor
ein Parameter .bergeben, der die Sortierung bestimmen wird:
Sub New(ByVal direction As Boolean)
Ist dieser Wert True, werde die Zahlenwerte _up und _down so ge-
setzt, dass die R.ckgabewerte aufsteigend bzw. absteigend sor-
tiert werden k6nnen, entsprechend dem Parameter des Konstruk-
tors beim Aufruf:
Array.Sort(_files, New FileSizeComparer(True))
Als letzten Schritt f.r die Umsetzung der gesamten L6sung wird
die Aufzhlungsklasse geschrieben. Dies sind die Objekte, die die
Methode GetEnumerator zur.ckgibt. Damit der Repeater funktio-
Sandini Bib
584 6 Programmierung von Web Forms
niert, muss es hier eine Logik geben, nach der eine Kollektion
durchlaufen werden kann. Dazu sind drei Methoden erforderlich:
E MoveNext()
Diese Methode bewegt einen internen Zeiger auf die Kollek-
tion einen Schritt weiter. Sie liefert True, wenn weitere Elemen-
te verf.gbar sind. Steht der Zeiger am Ende oder ist die
Kollektion leer, soll False zur.ckgegeben werden.
E Current
Diese Eigenschaft gibt das aktuelle Element zur.ck. Um die
Kollektion zu durchlaufen und die Werte zu entnehmen, ist
wechselseitig MoveNext und Current aufzurufen.
E Reset
Diese Methode setzt den Zeiger auf die Elemente wieder auf
das erste Element.
End Class
Listing 6.40: FileEnumerator, eine Klasse zum Auslesen einer Kollektion
(Ausschnitt aus FileCollectionClass.vb)
Es gibt nat.rlich auch Ereignisse, die den Auswahl- bzw. Bearbei- Ereignisse
tungsmodus starten, abbrechen oder g.ltig beenden.
Neu sind auch die Stilvorlagen, mit denen den Vorlagen Gestal- Stilvorlagen
tungsattribute hinzugef.gt werden k6nnen. Intern werden diese
Attribute in Cascading Style Sheets umgesetzt, sodass jeder mo-
derne Browser das Ergebnis verarbeiten kann.
Reine globale Stilattribute k6nnen Sie der folgenden Tabelle ent- Stilattribute
nehmen:
Gestaltung der F.r die Gestaltung der Vorlagen gibt es zwei M6glichkeiten. Ent-
Vorlagen weder geben Sie im Kopf des Steuerelementes weitere Stilattribute
an. Diese unterscheiden sich von den allgemeinen nur durch ei-
nen entsprechenden Prfix: ItemStyle, AlternatingItemStyle,
SelectedItemStyle, EditItemStyle, FooterStyle, HeaderStyle. Die
Hintergrundfarbe des Kopfbereiches wird dann durch Header-
Style-BackColor="farbname" festgelegt. Alternativ gibt es reine Stil-
Sandini Bib
Vorlagengebundene Daten-Steuerelemente 589
vorlagen, die denselben Effekt haben. Was Sie verwenden, ist Ge-
schmackssache. Die Stilvorlagen sind etwas .bersichtlicher:
font-weight:bold;">
Dateien im aktuellen Verzeichnis
</td>
</tr><tr>
<td style="font-family:Verdana;">
DataBinder.aspx
</td>
</tr>
...
Wenn Sie sehr lange Listen ausgeben, kann die Aufteilung auf
mehrere Spalten sinnvoll sein. Dazu sind weitere Attribute zu-
stndig:
E RepeatColumns="anzahl"
Hiermit wird die Anzahl der Spalten angegeben. Die Daten
der eindimensionalen Datenliste werden dann gleichmßig
.ber alle Spalten verteilt. Leere Spalten werden nicht ange-
zeigt; wenn nicht genug Daten da sind, erscheinen entspre-
chend weniger.
E RepeatDirection
Geben Sie hier die Richtung an, in der die Elemente auf die
Spalten verteilt werden. M6glich sind die Parameter Vertical
und Horizontal.
Bislang basierte die Ausgabe immer auf Tabellen. In den meisten RepeatLayout
Fllen ist das auch ausreichend. Wenn Sie eine etwas freiere Ge-
staltung w.nschen, k6nnen Sie das Attribut RepeatLayout mit dem
Parameter Flow verwenden. Dann werden Sequenzen aus
<span>-Tags erzeugt. Zeilenumbr.che, die dazwischen notwendig
sind, werden mit <br>-Tags umgesetzt. Die Attribute, die f.r Ta-
bellen typisch sind, wie GridLines oder Cellpadding, werden igno-
riert.
Der Einbau mehrerer Spalten scheitert auf den ersten Blick. Wenn Probleme mit
Sie nur Tabellenelemente ergnzen, stehen diese im Konflikt mit mehreren Spalten
den automatisch erzeugten. Der Inhalt von <ItemTemplate> steht
immer zwischen <td></td>-Paaren. Das Hinzuf.gen eines wei-
teren Paares bringt die Tabellen durcheinander. Im fließenden
Layout entsteht zwar eine richtige Tabelle, die <span>-Tags sind je-
doch weiter vorhanden und stehen zwischen den Reihen, was in
HTML nicht zulssig ist.
Die L6sung ist in einem weiteren Attribut zu finden: ExtractTem Umgang mit
plateRows. Wird der Parameter auf True gesetzt, extrahiert das Tabellen
Steuerelement vollstndige Tabellendefinitionen in den Vorlagen
Sandini Bib
592 6 Programmierung von Web Forms
und setzt daraus eine neue Tabelle zusammen. Die Definition der
in Abbildung 6.30 gezeigten Version sieht folgendermaßen aus:
Zwei Dinge sind hier zu beachten: Erstens m.ssen Sie in den Vor-
lagen jeweils vollstndige Tabellen definieren, die den gesamten
zu wiederholenden Bereich enthalten. Zweitens muss das Server-
Steuerelement Table verwendet werden und darauf aufbauend
nat.rlich TableRow bzw. TableCell. Die globalen Attribute der Stil-
vorlagen werden .bernommen, eigene Definition in den Tabellen-
Tags .berschreiben diese aber. Im Beispiel wurde mit Horizontal
Align="Right" die Ausrichtung der Zellen der rechten Spalte gen-
dert, sodass die Gr6ßenangabe rechtsb.ndig erscheint.
Sandini Bib
Vorlagengebundene Daten-Steuerelemente 593
Eine sehr flexible wenn auch langsame Methode, ist der Aus- Austauschen von
tausch der gesamten Vorlage. Sie k6nnen den Inhalt jeder Vorlage Vorlagen
dataList.ItemTemplate É
= Page.LoadTemplate ("Templates/DataListItem.ascx")
dataList.HeaderTemplate É
= Page.LoadTemplate ("Templates/DataListHeader.ascx")
dataList.Font.Name = "Verdana"
dataList.HeaderStyle.BackColor = Color.FromArgb(0xCCFFFF)
dataList.ItemStyle.BackColor = Color.FromArgb(0xFFCCCC)
dataList.AlternatingItemStyle.BackColor = Color.White
dataList.RepeatLayout = RepeatLayout.Table
dataList.GridLines = GridLines.Both
Der Name EditFile ist willk.rlich gewhlt. Sie m.ssen jetzt dazu
die passende Methode schreiben (je nach Art der Nutzung wre
noch Handles zu ergnzen):
Eigenschaften Der gew.nschte Effekt kommt zustande, indem Sie dem Steuer-
element .ber die Eigenschaft EditItemIndex mitteilen, f.r welche
Reihe die Vorlage <EditItemTemplate> genutzt werden soll. Wenn
der Index auf -1 gesetzt wird, verschwindet die Vorlage wieder
und ItemTemplate oder, wenn vorhanden, AlternatingItemTemplate
wird wieder angezeigt. Der Index kann auf einen fortlaufenden
Wert zwischen 0 und der Anzahl der Reihen minus Eins gesetzt
werden. die ausgewhlte Reihe kann durch Zugriff die Argumen-
te des Ereignisses erfolgen, im Beispiel das Objekt e. Drei Eigen-
schaften sind verf.gbar:
E Item
Diese Eigenschaft erlaubt den Zugriff auf das Datenelement
dieser Zeile, dessen Eigenschaft ItemIndex ergibt dann den In-
dex der ausgewhlten Zeile.
E CommandArgument
Wenn Sie mit dem Attribut CommandArgument ein Argument zum
Kommando .bergeben haben, steht es in dieser Eigenschaft.
Das nchste Beispiel zeigt die Verwendung.
E CommandName
Der Name des Kommandos, im Beispiel ist dies die Zeichen-
kette "edit".
<asp:DataList ... É
OnCancelCommand="CancelFile" É
OnUpdateCommand="UpdateFile" É
... >
Sandini Bib
Vorlagengebundene Daten-Steuerelemente 597
Rhnlich ist auch UpdateFile aufgebaut, nur wird hier neben dem
R.cksetzen des Index der Name der Datei verndert. Freilich hat
dies nichts mit DataList zu tun, sondern ist nun Code aus dem ei-
gentlichen Programm. Sie ahnen vielleicht schon, was hier ent-
steht. Es handelt sich um eine fr.he Phase eines serverseitigen Da-
teiexplorers.
Das eigentlich knifflige ist jedoch der Zugriff auf die alten und
neuen Werte der Liste. Zu dem Zeitpunkt, an dem die Ereignisse
ausgel6st werden, wurde die Seite schon verarbeitet. Zuerst ben6-
tigen Sie eine Methodik, mit der auf das TextBox-Objekt zugegrif-
fen werden kann. Dazu wird die Methode FindControl eingesetzt,
die in der Ereignisquelle nach einem Steuerelement sucht:
Jetzt steht das Objekt zur Verf.gung und damit k6nnen Sie auch
auf den neuen (!) Inhalt zugreifen:
tb.Text
ViewState("dl") = fc
Abbildung 6.31: Die Liste im ViewState – auch so kann man Daten erhalten
Jetzt bleibt noch die Frage, wie die Daten wieder zur.ckgeholt Anzeigestatus
werden. Bei den Server-Steuerelementen passiert das automatisch. zurckholen
Ihre selbstdefinierten ViewState-Eintrge m.ssen Sie auch selbst
wieder zur.ckholen. Im Else-Zweig, wo der Teil von Page_Load
ausgef.hrt wird, wenn die Anforderung per POST kam, steht
dann Folgendes:
dataList.DataSource = ViewState("dl")
dataList.DataBind()
Der Name »dl« ist .brigens willk.rlich gewhlt, er muss nur ein-
deutig sein.
dataList.DataSource = Session("dl")
dataList.DataBind()
Session("dl") = fc
Der Zugriff auf die Kollektion fc in der gezeigten Form setzt vo-
raus, dass eine Standardeigenschaft definiert wurde. Dies ist in
der Klasse FileCollection die Eigenschaft Item. Vergleichen Sie da-
zu die Ausf.hrungen zu FileCollectionClass.vb weiter vorn.
<asp:button CommandName="ToFileList" É
CommandArgument="add" É
Runat="server" ID="AddButton" É
Text="Hinzuf:gen"/>
<asp:button CommandName="ToFileList" É
CommandArgument="remove"
Runat="server" ID="RemoveButton" É
Text="Entfernen"/>
Mit CommandName wird ein beliebiger Name als »Kommando« fest- Kommandos
gelegt. Dem Kommando kann dann noch mit CommandArgument ein verarbeiten
Parameter mitgegeben werden. Im Beispiel heißt das Kommando
»ToFileList«. Beide Schaltflchen l6sen also dasselbe Kommando
aus. Damit unterschiedliche Aktionen starten, wird das Komman-
doargument verwendet. F.r ein so einfaches Muster ist das nicht
zwingend erforderlich, es dient hier nur der Demonstration. In
der Praxis w.rde man bei wenigen Aktionen besser gleich ver-
schiedene Kommandonamen verwenden.
Es muss nun noch eine Methode erstellt werden, die den Namen
»DoCommand« trgt. Der Name ist nat.rlich wieder willk.rlich
gewhlt. Das Beispiel nutzt die Kommandos, um ausgewhlte Na-
men der Dateiliste in eine weitere Liste zu .bernehmen, die unter-
halb der Tabelle erscheint. Wie schon im letzten Abschnitt gezeigt,
werden Sitzungsvariablen verwendet, um den Zustand der Liste
zu erhalten. Die Ausgabe erfolgt mit einem Repeater-Steuerele-
ment mit dem Namen Selection, das hier nicht weiter erlutert
werden soll.
fcSelect.Remove(fc(ec.Item.ItemIndex).FileName)
End Select
End Select
Selection.DataSource = fcSelect
Selection.DataBind()
Session("fcSelect") = fcSelect
End Sub
Listing 6.43: Verarbeitung der Kommandos der Schaltfl@chen (Ausschnitt aus
DataListEditorCommand.aspx.vb)
Session("fc") = fc
Session("fcSelect") = fcSelect
Eigenschaften der Bei der Definition des Methodenkopfes ist zu beachten, dass das
Kommandos Ereignis vom Typ DataListCommandEventArgs sein muss. Dieses Er-
eignis besitzt mehrere Eigenschaften, die den Zugriff auf die ent-
sprechenden Parameter der Schaltflchen haben:
E CommandName
Dies ist der Name des Kommandos – als Zeichenkette (Typ
String) – wie er mit CommandName im Button-Steuerelement defi-
niert wurde.
E CommandArgument
Dies ist ein optionales Arguments des Kommandos – als Zei-
chenkette (Typ String) – wie er mit CommandArgument im Button-
Steuerelement definiert wurde.
E CommandSource
Dies ist die Datenquelle selbst, bei einer Schaltflche vom Typ
System.Web.UI.WebControls.Button. Sie k6nnen dar.ber auf Ei-
genschaften des Steuerelementes zugreifen, wenn dies erfor-
derlich sein sollte.
E Item
Hiermit erlangen Sie Zugriff auf die Datenreihe des DataList-
Steuerelementes. Im Beispiel wird die Eigenschaft ItemIndex
der aktuellen Datenreihe benutzt, um auf das Element selbst
Sandini Bib
Vorlagengebundene Daten-Steuerelemente 603
Wenn Sie bisher mit LinkButton gearbeitet haben und nun auf Button
umstellen, wird Ihr Programm mglicherweise nicht mehr funktionieren.
Die fertigen Beispiele dieses Buches funktionieren, weil in jedem Fall der
Aufbau der Liste nur dann erfolgt, wenn die Daten mit HTTP-GET an-
gefordert werden. Beim folgenden Zur#cksenden des Formulars (Post-
Back) wird nur auf die gespeicherte Liste zugegriffen. F#r die Analyse
und Ausgabe von Schaltfl*chen ist dies zwingend erforderlich. Der
Render-Prozess kann bei einem erneuten Aufbau die urspr#nglichen
Button-Definitionen nicht mehr erkennen und erstellt einfache <input
type="submit">-Schaltfl*chen daraus. Damit geht die PostBack-Funk-
tionalit*t verloren. Der Browser sendet das Formular zwar ab, die Ver-
kn#pfung mit der Ereignisbehandlungsmethode ist jedoch weg.
Anwendung Der Effekt des gezeigten Programms besteht darin, dass Sie aus ei-
ner dynamischen Liste von Dateinamen mittels Schaltflche wel-
che auswhlen k6nnen und diese einer weiteren Liste hinzugef.gt
werden. Ebenso einfach ist das Entfernen m6glich. Ein typischer
Einsatz wre ein kleiner Shop mit nur einer Warengruppe, dessen
Artikel durch eine »Ein-Klick-System« in den Warenkorb .ber-
nommen werden sollen.
Zusammenfassung
Dieser Abschnitt hat in umfassender Weise das DataList-Steuer-
element und typische Techniken im Umgang damit vorgestellt.
Das nchste Element, DataGrid, basiert auf hnlichen Prinzipien,
ist jedoch noch komplexer. Viele Eigenschaften sind mit DataList
identisch, diese sollen nicht in dieser Ausf.hrlichkeit wiederholt
Sandini Bib
Vorlagengebundene Daten-Steuerelemente 605
6.6.5 DataGrid
Das DataGrid-Steuerelement basiert, ebenso wie DataList, auf Vor-
lagen. Diese sind allerdings nicht nur zeilenweise orientiert, son-
dern erlauben auch eine spaltenweise Ausrichtung. Damit ergibt
sich eine besonders hohe Flexibilit t im Zusammenhang mit kom-
plexeren Datenbankabfragen. Allerdings gilt zur Art der Daten-
quelle das zuvor bereits Gesagte – neben jeder Klasse, die IEnu
merable implementiert, kann gebunden werden.
Elementare Eigenschaften
Das Steuerelement besitzt einige elementare Eigenschaften, die eine
Menge Programmierarbeit sparen, wenn man sie richtig einsetzt:
Automatisches DataGrid
Beispiel Das Beispiel DataGridSimplest.aspx zeigt, wie einfach DataGrid ver-
wendet werden kann. Die Definition ist auf das unbedingt Not-
wendige reduziert:
<asp:DataGrid Runat="server" ID="dataGrid"/>
Abbildung 6.33: Aufbau der Datenausgabe ohne Parameter – dies kann DataGrid allein
Es ist absehbar, dass Sie sich damit nicht zufrieden geben mssen.
Wenn ein Steuerelement bereits ohne jede Vorgabe eine so kom-
plexe Ausgabe erzeugt, kann man mit weiteren Techniken er-
staunlich viel erreichen.
E <asp:BoundColumn>
E <asp:ButtonColumn>
<asp:DataGrid ...
<Columns>
<asp:BoundColumn .../> ...
</Columns>
</asp:DataGrid>
Lassen Sie sich nicht davon t uschen, dass es sich offensichtlich um Nur im DataGrid
ein Server-Steuerelement handelt. Sie k nnen dieses nur im Zusam- verwendbar
menhang mit DataGrid verwenden. Das Binden der Datenquelle ist
sehr einfach, da sie auf die bliche Datenbindungssyntax verzich-
tet, solange Sie nicht von der Standardbindung abweichen. Aller-
dings entfallen damit auch alle Gestaltungsm glichkeiten. Ab-
gesehen davon k nnen Sie alles selbst definieren und damit
maximale Flexibilit t in der Gestaltung erreichen.
Folgende Attribute k nnen eingesetzt werden:
E DataField
Hiermit wird die Spalte in der Datenquelle bestimmt. Bei Ob-
jekten, wie im Beispielcode, kann dies der Name einer Eigen-
schaft sein, bei SQL-Abfragen entspricht es den Spaltennamen
der Tabelle oder Sicht.
E DataFormatString
Falls die Ausgabe formatiert werden muss, kann hier eine For-
matzeichenfolge stehen. Hinweise dazu finden Sie in der Refe-
renz im Anhang. Der dynamische Parameter hat die Nummer 0.
E DataKeyField
Dieses Feld bestimmt die Schlsselspalte, die meist mit dem
Prim rschlssel der unterliegenden Tabelle bereinstimmt.
Dadurch kann bei der Auswahl einer Datenreihe die Zuord-
nung zur Datenquelle beim L schen oder Aktualisieren be-
stimmt werden.
Sandini Bib
608 6 Programmierung von Web Forms
E HeaderText
Die Spaltenberschrift wird mit diesem Attribut festgelegt.
E HeaderStyle-XXX, ItemStyle-XXX, FooterStyle-XXX
Eine ganze Palette von Stilattributen, die Kopf- oder Fußzeile
bzw. die Reihen formatieren.
FooterText, Standardm ßig ist der Kopfbereich sichtbar und der Fußbereich
FooterStyle unsichtbar. Wenn Sie eine Fußzeile anzeigen m chten, reicht es
nicht aus, FooterText zu setzen. Sie mssen im Kopf des Tags die
Eigenschaft ShowFooter explizit einschalten:
Wenn Sie die Fußzeile nicht bentigen, knnen Sie diese trickreich zur
t (bergabe spaltengebundener Daten verwenden, indem Sie die Informa-
tionen an Spalten binden und die Zeile dann unsichtbar machen. Ein
Anwendungsbeispiel daf$r finden Sie im Abschnitt 2.3.3, »Ein erstes
Datenbankprojekt« ab Seite 114.
Sandini Bib
Vorlagengebundene Daten-Steuerelemente 609
E <HeaderTemplate>
E <ItemTemplate>
E <EditItemTemplate>
E <FooterTemplate>
Auch hier fehlt – im Unterschied zu DataList – die Definition der Keine alternativen
alternativen Zeilen. Sie k nnen diese nur ber die Stile gestalte- Zeilen
risch absetzen. Individuell kann dagegen fr jede Spalte der Kopf-
und Fußbereich gestaltet werden. In Fußzeilen lassen sich bei-
spielsweise Summen platzieren. Wenn Ihre Datenquelle den di-
rekten Abruf nicht gestattet, k nnen Sie auch eine Methode direkt
aufrufen. Das folgende Beispiel zeigt eine solche Version:
Der Abruf der Daten erfolgt unver ndert; neu ist lediglich die Me-
thode FileSizeSummary:
Abbildung 6.35: Platzierung der Spaltensumme durch direkten Aufruf einer Funktion im
Datenbindungsausdruck
<asp:DataGrid ... É
AllowSorting="True" É
OnSortCommand="DoSort" É
...>
Nach diesem Schritt sind noch die Spalten zu bestimmen, die die
Sortierlinks tragen. Prinzipiell kann dies jede Spalte sein. Es ob-
liegt Ihnen dafr Sorge zu tragen, dass die vom Benutzer erwarte-
te Aktion auch ausgefhrt wird. Das DataGrid-Steuerelement prft
nicht, ob die Sortierung der fiktiven Spalte A auch tats chlich A
und nicht C sortiert. Im n chsten Beispiel werden drei Spalten
definiert, zwei mit Sortierlinks und eine mit der Anzeige des Sor-
tierwertes. Dadurch k nnen gleich zwei verschiedene Komman-
dos abgesetzt werden: Auf- und Abw rtssortierung. Zuerst das
DataGrid auf einen Blick:
Ob die Spalte, die die Sortierung ausl st, Daten zur Anzeige ent-
h lt oder nicht, ist irrelevant. Die angezeigten Daten werden nicht
zur Sortierung verwendet, sondern die zugrunde liegende Daten-
quelle. Eine Spaltenberschrift mutiert zum Link, wenn Sie das
Attribut SortExpression einbauen. Der Parameter wird als Eigen-
schaft SortExpression des Ereignisarguments DataGridSortCommand
EventArgs bergeben.
Die Spalte, auf die der Benutzer geklickt hat, wird also anhand
des SortExpression-Parameters erkannt.
Etwas trickreich ist die Gestaltung bei der gezeigten Form mit Gestaltungstipps
mehreren Sortierkriterien pro Spalte. Da pro Spalte nur ein Sor-
tierlink verwendet werden kann, wurden im Beispiel drei Spalten
verwendet. Die Links stehen ber Spalten ohne Inhalt. Damit es
optisch so wirkt, als w re es eine Spalte, wurden die vertikalen
Trennlinien unterdrckt: GridLines="Horizontal" im Kopf des Steu-
erelements sorgt dafr. Um die vertikale Linie neben der linken
Spalte zu erhalten, wird dessen Vorlage ItemStyle mit einem Rand
versehen:
<asp:TemplateColumn>
<ItemStyle HorizontalAlign="Right" Font-Bold="True"/>
<ItemTemplate>
<asp:Label Runat="server" ID="number"/>.
</ItemTemplate>
</asp:TemplateColumn>
Listing 6.49: Spalte, die zur Laufzeit mit Daten außerhalb der Datenquelle gef7llt wird
(Ausschnitt aus DataGriditemBind.aspx)
Wie es Hier wird zuerst berprft, welchen Typ die gerade verarbeitete
funktioniert Reihe hat. Der Zugriff erfolgt ber die Eigenschaft ItemType des
Objekts Item, das die Zeile repr sentiert. Die Aufz hlung ListItem
Type kann zum Vergleich verwendet werden. Auf diesem Wege
sind natrlich auch die Kopf- und Fußzeilen zug nglich, und
zwar genau in der Reihenfolge, wie sie auf der Seite erscheinen.
Das Label-Steuerelement wird ber FindControl ermittelt. Sie k n-
nen dann an dieser Stelle beliebige Daten zuweisen. Fr fortlau-
fende Nummern ist ItemIndex ideal.
6.7 Kontroll-Steuerelemente
(Validation Controls)
In den vorangegangenen Abschnitten wurden Formularelemente,
bestehend aus HTML Server- oder Web Server-Steuerelementen,
bereits intensiv genutzt. Es liegt in der Natur der Sache, dass der
von Benutzern erfasste Inhalt nicht immer kritiklos angenommen
werden kann. Angefangen von einfachen Tippfehlern bis hin zu
mutwilligen Falschangaben wird ein Programm viele falsche Da-
ten verkraften mssen. Natrlich ist es m glich, die gesendeten
Daten zu berprfen und dann entsprechend zu reagieren. In der
Praxis enthalten aber Formulare viele Felder, die teilweise mit-
einander in Beziehung stehen. Denken Sie an eine vergleichsweise
einfache Kennwort nderung. Hier mssen Sie zum einen die Be-
dingungen des Kennworts selbst kontrollieren, beispielsweise ei-
ne Mindestanzahl Zeichen. Außerdem mssen das Kennwortfeld
und ein Kontrollfeld miteinander verglichen werden. Das kann in
Sandini Bib
Kontroll-Steuerelemente (Validation Controls) 617
</head>
<body>
Bitte geben Sie die Lieferadresse an:<br/>
<form runat="server">
<table border="1">
<tr>
<td>Name</td>
<td>
<asp:textbox runat="server" É
id="f_name" />
</td>
<td>
<asp:requiredfieldvalidator runat="server" É
id="v_name" É
controltovalidate="f_name" É
display="dynamic">
Geben Sie einen Namen ein!
</asp:requiredfieldvalidator>
</td>
</tr>
<tr>
<td>Strasse</td>
<td>
<asp:textbox runat="server" id="f_street" />
</td>
<td>
<asp:requiredfieldvalidator runat="server" É
id="v_street" É
controltovalidate="f_street" É
display="dynamic">
Geben Sie eine Straße an!
</asp:requiredfieldvalidator>
</td>
</tr>
</table>
<asp:button runat="server" id="send" text="Bestellen"/>
</form>
</body>
</html>
Listing 6.51: Formular mit zwei kontrollierten Eingabefeldern
(ValidationControlRequired.aspx)
<asp:requiredfieldvalidator runat="server" É
id="v_street" É
controltovalidate="f_street" display="dynamic">
Geben Sie eine Straße an!</asp:requiredfieldvalidator>
Die Tabelle wird durch das in der rechten Spalte platzierte Kon-
troll-Steuerelement dynamisch erweitert. Das kann, wenn die Ta-
belle ein wichtiges Gestaltungselement der Seite ist, den gesamten
Aufbau zerst ren. Wrde als Attribut display="static" verwendet
werden, s he die Tabelle folgendermaßen aus:
<body>
Bitte geben Sie die Lieferadresse an:<br/>
<form runat="server">
Sandini Bib
Kontroll-Steuerelemente (Validation Controls) 623
<tr>
<td>Kennwort</td>
<td>
<asp:textbox runat="server" id="f_password1" É
textmode="password"/><br/>
<asp:textbox runat="server" id="f_password2" É
textmode="password"/>
</td>
<td>
<asp:comparevalidator id="Compare1" type="string" É
runat="server" É
controltovalidate="f_password1" É
controltocompare="f_password2">
Die Kennwortfelder stimmen nicht Lberein
</asp:comparevalidator>
</td>
<tr>
Listing 6.54: Mehrere Pr7fungen mit dem CompareValidator Steuerelement
(Ausschnitt aus ValidationControlsCompare.aspx)
Sollen dagegen zwei Felder verglichen werden, sind zwei andere Zwei Felder
Attribute beteiligt: controltovalidate und controltocompare: vergleichen
... controltovalidate="f_password1"
controltocompare="f_password2" ...
Die Kombination mit type ist m glich, dann wird neben der
Gleichheit der Felder auch die Bbereinstimmung des Datentyps
geprft. Das Attribut operator ist dann optional. Fr alle anderen
F lle, in denen ein Vergleich erfolgen soll, k nnen Sie operator mit
folgenden Parametern ausstatten:
Der Vergleich kann nicht nur zwischen Feldern, sondern auch mit
einem konstanten Wert erfolgen. Dazu wird statt controltocompare
das Attribut valuetocompare verwendet. Fr den Vergleich von
Zahlen ist das Attribut type erforderlich; operator mit einem der
genannten Parameter sowieso:
Sandini Bib
626 6 Programmierung von Web Forms
Oder Sie bauen ein Container-Tag, das die Meldung enth lt:
Das Bereichskontroll-Steuerelement
(RangeValidator Control)
Manchmal reicht der Vergleich von Feldern mit Festwerten nicht
aus. Der RangeValidator prft, ob Werte in einem bestimmten Be-
reich liegen. So k nnte die Prfung der Postleitzahlen im letzten
Beispiel verbessert werden, indem statt der Prfung des Daten-
typs eine Einschr nkung auf den Bereich zwischen 1.000 und
99.999 erfolgt. Der RangeValidator arbeitet hnlich dem Compare
Validator, verwendet aber zur Kontrolle zwei spezielle Attribute,
die den Wertebereich eingrenzen: MinimumValue und MaximumValue.
<tr>
<td>PLZ</td>
<td>
<asp:textbox runat="server" id="f_zipcode" width="5"/>
</td>
<td>
<asp:rangevalidator runat="server" id="v_zipcode" É
type="Integer" É
minimumvalue="1000" É
maximumvalue="99999" É
controltovalidate="f_zipcode" É
Sandini Bib
Kontroll-Steuerelemente (Validation Controls) 627
display="dynamic">
Postleitzahl im falschen Wertebereich
</asp:rangevalidator>
<asp:requiredfieldvalidator runat="server" É
id="vr_zipcode" É
controltovalidate="f_zipcode" É
display="dynamic">
Postleitzahl nicht angegeben
</asp:requiredfieldvalidator>
</td>
</tr>
Listing 6.55: Kontrolle eines Wertebereiches (Ausschnitt aus
ValidationControlsVcCompare.aspx)
H ufig wird ein Eingabefeld fr die E-Mail-Adresse ben tigt. Der
dazu erforderliche regul re Ausdruck sieht folgendermaßen aus:
^
[_a-zA-Z0-9-]+
(\.
[_a-zA-Z0-9-]+
)*
@
(
[a-zA-Z0-9-]+
\.
)+
(
[a-zA-Z]{2,3}
)
$
Listing 6.56: Regul?rer Ausdruck zum Pr7fen einer E-Mail-Adresse
Sandini Bib
628 6 Programmierung von Web Forms
<tr>
<td>E-Mail</td>
<td>
<asp:textbox runat="server" id="f_email" />
</td>
<td>
<asp:regularexpressionvalidator runat="server" É
id="v_email"
validationexpression =
"^[_a-zA-Z0-9-]+(\.[_a-zA-Z0-9-]+)*@([a-zA-Z0-9-]
+\.)+([a-zA-Z]{2,3})$" É
controltovalidate="f_email" display="dynamic">
Diese E-Mail-Adresse ist nicht gLltig
</asp:regularexpressionvalidator>
</td>
</tr>
Listing 6.57: Pr7fung einer E-Mail-Adresse (Ausschnitt aus ValidationControls-
Compare.aspx, der Ausdruck muss in einer Zeile geschrieben werden)
muss. Dies kann nicht mit einem Suchmuster erfolgen. Sie mssen
dazu eine eigene Funktion schreiben, die die Prfziffer selbst be-
rechnet und vergleicht.
Das folgende Beispiel zeigt die Prfung von ISBN-Nummern. Zu- Serverseitige
erst das Listing des HTML-Codes. Die Prfung ist in eine hinter- Prfungen
legte Code-Datei ausgelagert, die danach vorgestellt wird:
<html>
<head>
<title>Validation Control - 3</title>
</head>
<body>
Nach welcher ISBN möchten Sie suchen?<br/>
<form runat="server">
<asp:textbox runat="server" id="f_isbn" />
<asp:button runat="server" id="send" text="PrLfen"/>
<br/>
<asp:customvalidator runat="server" id="v_isbn" É
onservervalidate="checkisbn" É
display="dynamic">
ISBN-Nummer ist falsch
</asp:customvalidator>
(Geprüfte Nummer:
<asp:label id="l_isbn" runat="server"/>)
</form>
</body>
</html>
Listing 6.58: HTML-Teil mit der Definition des benutzerdefinierten Kontroll-
Steuerelements (ValidationControlCompareJS.aspx)
Sandini Bib
630 6 Programmierung von Web Forms
Definiert wird hier neben dem Eingabefeld (f_isbn) und der Sen-
deschaltfl che (send) auch ein Label, das die gew hlte Nummer
oder eine Fehlermeldung anzeigt. Alle Berechnungen werden in
der Klasse Checker definiert:
Die Datei beginnt mit dem Zugriff auf die ben tigten Namensr u- Wie es
me. Die verwendeten Zeichenketten-Methoden aus der Klasse funktioniert
System.String sind im Basisnamensraum System definiert. Die Klas-
se checker muss außerdem von Page erben und natrlich ffentlich
zug nglich sein:
Zuerst erfolgt der Zugriff auf das Eingabefeld ber die Eigen-
schaft Text:
Dim isbn As String = f_isbn.Text
l_isbn.Text = isbn10
Validierung auf Beachten Sie hier, dass Sie nicht nur IsValid schreiben, denn dann
Element- oder wird Page.IsValid verwendet. Das ist zwar nicht prinzipiell falsch,
Seitenebene
denn mit der Ungltigkeit eines Kontroll-Steuerelements wird
auch der Prfzustand der gesamten Seite ungltig, aber im Bei-
spiel wird Page.IsValid nicht ausgewertet. Um die Fehlermeldung
zu provozieren, muss das Objekt e angesprochen werden.
Dann folgt der Vergleich. Das Ergebnis wird gleich fr IsValid
verwendet:
<html>
<head>
<title>Validation Control - 3</title>
<script language="JavaScript">
function checkisbn(sender, e)
{
isbn = document.checkform.f_isbn.value;
isbn10 = isbn.replace(/-/g, "");
if (isbn10.length != 10)
{
alert("Anzahl Ziffern falsch: " É
+ isbn10.length + " (" + isbn10 + ")");
e.IsValid = false;
} else {
checkdigit = 11-((10*isbn10.substr(0,1) + 9 * É
isbn10.substr(1,1) + 8 * É
isbn10.substr(2,1) + 7 * É
isbn10.substr(3,1) + 6 * É
isbn10.substr(4,1) + 5 * É
isbn10.substr(5,1) + 4 * É
isbn10.substr(6,1) + 3 * É
isbn10.substr(7,1) + 2 * É
isbn10.substr(8,1) ) % 11);
checkdigit = (checkdigit == 11) ? 0 : checkdigit;
comparedigit = (isbn10.substr(9,1) == "X") ? 10 :É
isbn10.substr(9,1);
e.IsValid = (checkdigit == comparedigit);
}
}
</script>
</head>
<body>
Nach welcher ISBN möchten Sie suchen?<br/>
<form runat="server" id="checkform">
<asp:textbox runat="server" id="f_isbn" />
<asp:button runat="server" id="send" text="PrLfen"/>
<br/>
<asp:customvalidator runat="server" id="v_isbn" É
onservervalidate="checkisbn" É
clientvalidationfunction="checkisbn" É
display="dynamic">
ISBN-Nummer ist falsch
</asp:customvalidator>
(Geprüfte Nummer:
Sandini Bib
634 6 Programmierung von Web Forms
Wie es Die Funktion checkisbn selbst unterscheidet sich nur wenig von
funktioniert der bereits in VB.NET gezeigten. Beachtenswert ist der Zugriff auf
die Feldwerte, der ber das DOM-Modell des Browser erfolgt:
isbn = document.checkform.f_isbn.value;
document.getElementById("l_isbn").innerHTML É
= "Anzahl Ziffern falsch: " + isbn10.length;
Im Sinne eines gutes Programmstils sollten Sie immer client- und ser-
t verseitige Steuerelemente realisieren. Wenn der Browser JavaScript un-
terst$tzt, spart es Bandbreite und die Verarbeitung der Seite wirkt auf
den Benutzer schneller. Ist JavaScript nicht einsetzbar, funktioniert es
trotzdem.
Sandini Bib
Komplexe Steuerelemente (Rich Controls) 635
<html lang="de">
<head>
<title>Kalender</title>
<basefont face="Arial">
</head>
<body>
<h1>Kalender</h1>
<form runat="server">
<asp:calendar id="kalender" runat="server" É
onSelectionChanged="zeigeDatum"/>
Sandini Bib
636 6 Programmierung von Web Forms
Hier passiert auch nicht viel. Zuerst der Zugriff auf das aus-
gew hlte Datum, das zugleich zum aktuellen gemacht wird:
kalender.TodaysDate = kalender.SelectedDate
Das war’s auch schon. In der Referenz finden Sie zahlreiche Ei-
genschaften zur Gestaltung und Methoden zur Behandlung der
ermittelten Datumswerte.
Sandini Bib
Komplexe Steuerelemente (Rich Controls) 637
Jedes Element des Kalenders kann ber einen eigenen Stil gesteu- Stilvorlage
ert werden. Die in Abbildung 6.41 gezeigte Version ist nahezu
ungestaltet, außer dem global bestimmten Font wurden keine Stil-
vorlagen verwendet. Die folgende Tabelle zeigt alle zul ssigen Sti-
le und deren Bedeutung.
Stil Bedeutung
<TodayDayStyle> Der aktuelle Tag (Heute)
<WeekEndDayStyle> Das Wochenende
<DayHeaderStyle> Bberschrift mit Wochentagsnamen
<SelectedDayStyle> Der ausgew8hlte Tag
<DayStyle> Alle anderen Tage
<TitleStyle> Der Titel des Kalenders
<NextPrevStyle> Stil der Bl8ttersymbole »<« und »>«
<OtherMonthDayStyle> Wechsel auf einen anderen Monat
<SelectorStyle> Auswahl f.r eine Woche oder den gesamten Monat
E ShowDayHeader
Zeigt, wenn true, die Bberschrift mit den Wochentagsnamen
an.
E ShowGridLines
Zeigt die Gitterlinien zwischen den Tagen an oder blendet sie
aus.
Sandini Bib
638 6 Programmierung von Web Forms
E ShowNextPrevMonth
Schaltet die Bl tterfunktion »vorhergehender Monat« und
»n chster Monat« ein oder aus.
E ShowTitle
Schaltet den Titel des Kalenders ein oder aus.
Beispiel Der Umgang mit dem Kalender ist in einigen Details nicht trivial,
vor allem, wenn bestimmte Designansprche vorgegeben sind,
die das Element nicht direkt untersttzt. Das folgende Beispiel
zeigt, wie sie Calendar programmieren k nnen und welche Proble-
me es dabei gibt.
</TD>
</TR>
<TR>
<TD align="middle">
<asp:HyperLink Runat="server" ID="TransferDate" É
Target="GetDateFromCalendar" Font-Names="Verdana" É
Font-Bold="True">Noch keine Auswahl getroffen É
</asp:HyperLink>
</TD>
<TD>
<input type="submit" name="Close" onclick="self.
close()" É
value="Schließen">
</TD>
</TR>
</TABLE>
</form>
</body>
</HTML>
Listing 6.65: Die Darstellung des Kalenders (GetDateCalendard.aspx)
= String.Format("GetDateFromCalendar.aspx?date={0}",
NewDate)
TransferDate.Text = NewDate + " Lbernehmen?"
Calendar1.TodaysDate = Calendar1.SelectedDate
End Sub
TransferDate.NavigateUrl É
= String.Format("GetDateFromCalendar.aspx?date={0}",
NewDate)
Zuletzt wird das aktuelle Datum des Kalenders auf die Auswahl
gesetzt, damit die Anzeige nicht zurckspringt, was recht irritie-
rend fr den Benutzer ist:
Calendar1.TodaysDate = Calendar1.SelectedDate
Mit einem Klick auf den mit »Heute« beschrifteten Link kann das
aktuelle Datum wieder eingestellt werden. Die Ereignisbehand-
lungsmethode dafr enth lt folgenden Code:
Calendar1.TodaysDate = Now
Die Steuerung eines zweiten Fensters auf so direktem Wege, mit Probleme mit
GET, ist zwar einfach, aber nicht ideal. Denn beim erneuten Aufruf diesem Programm
der ersten Seite per GET gehen die Feldwerte und der Anzeige-
status verloren. Die Bbergabe per POST scheidet aus, weil sich
durch den gegenseitigen Aufruf Probleme mit dem Anzeigestatus
ergeben. Diese Funktion dient nur der Erhaltung eines Status, wenn
sich eine Seite selbst aufruft.
In der Praxis k nnen Sie die Bbergabe der Werte ber zwei Wege L2sungen
erreichen:
E Verwendung von Sitzungsvariablen
Sitzungen sind ein einfaches Mittel zur L sung. Sie finden da-
zu ausfhrliche Informationen in Abschnitt 8.4, »Sitzungen
(Sessions)« ab Seite 778.
E Referenzierung anderer Seiten ber den so genannten Seiten-
kontext
Die Referenzierung ist der »moderne« Weg, der den Paradig-
men von ASP.NET folgt. Diese Technik wird in Abschnitt
8.3.8, »Kontext-Handler und Seitenreferenzierung« ab Seite
773 behandelt.
AdRotator
Dieses Element dient der Speicherung von Werbeinformationen.
Bber eine Steuerdatei kann das Einblenden von Werbebanners
kontrolliert werden. Das Element hat folgenden Namen:
<asp:AdRotator>
<Advertisment>
<Ad>
<ImageUrl>
Bildpfad </ImageUrl>
...
</Advertisment>
XML
Dieses Element dient der Anzeige von XML-Daten innerhalb einer
Seite: Es wird folgendermaßen benannt:
<asp:xml>
Als Parameter werden die Angabe der XML-Datei und die einer
XSLT-Datei erwartet. Die XSLT-Datei sollte die Daten in ein les-
bares Format berfhren.
7 Erweiterte
Web Form-Programmierung
Nach der Einfhrung in die Welt der »Web Forms« – also der Pro-
grammierung nach der Gestaltung der Benutzerschnittstelle – soll
nun auf einige erweiterte Techniken eingegangen werden. In die-
sem Kapitel wird die Erstellung eigener Steuerelemente vor-
gestellt und gezeigt, wie Sie Steuerelemente nachtr glich installie-
ren und verwenden.
7.1 Schnellstart
Dieser Abschnitt gibt einen kompakten Bberblick ber das Thema
und zeigt sinnvolle Verknpfungen mit erg nzenden und vor-
bereitenden Kapiteln. Der Wegweiser in die Referenz hilft, die pas-
senden Seiten in der MSDN-Online-Referenz besonders schnell zu
finden.
Das sich die Browser nachwievor in der Art der Darstellung von
komplexerem HTML-Code etwas unterscheiden, wird auf die
browserabh ngige Programmierung eingegangen. Dabei geht es
darum, die Leistungen des Browsers zu erkennen und den dazu
passenden Code ablaufen zu lassen. Abschnitt 7.3, »Browserorien-
tiert programmieren« ab Seite 662 widmet sich diesem Thema.
Sandini Bib
646 7 Erweiterte Web Form-Programmierung
Auf gleicher Basis aber auf anderem Weg wird WebControl abgelei-
tet, die Klasse, die als Basis kundenspezifischen Steuerelemente
dient:
7.2.1 Grundlagen
Benutzer-Steuerelemente sind so einfach und flexibel, dass der Ein-
satz sich auch schon bei kleineren Projekten lohnen kann. Praktisch
werden hier Objekte definiert, die hnlich wie die Web Server-Steu-
erelemente einen eigenen Namensraum besitzen. Wenn die Erwei-
terung von HTML ber den Namensraum »asp:« gelingt, sollte es
auch m glich sein, eigene Namensr ume zu deklarieren. Tats ch-
lich ist dies kein Trick, sondern vom Systemdesign vorgegeben. Ei-
ne solche Erweiterung wird als Benutzer-Steuerelement bezeichnet.
Welches Pr fix verwendet wird, k nnen Sie selbst bestimmen.
Da Benutzer-Steuerelemente per Definition zur Gruppe der Web Aufbau und
Server-Steuerelemente geh ren, verhalten sie sich auch hnlich. Einsatz
Der Inhalt eines Benutzer-Steuerelementes darf nur aus HTML-
Tags bestehen, wie er zwischen den <body>-Tags stehen kann.
<html> und <body> selbst drfen nicht auftreten. Ebenso sollte das
<form>-Tag vermieden werden, da die ASP.NET-Komponente er-
wartet, das Benutzer-Steuerelemente innerhalb oder außerhalb ei-
nes Formulars erscheinen, aber dieses nicht selbst bilden. Benut-
zer-Steuerelemente sind in ihrem Einsatzspektrum dennoch kaum
eingeschr nkt. Was immer Sie in Ihrem Projekt mehr als einmal
ben tigen, k nnen Sie so definieren. Durch die M glichkeit, auf
die enthaltenen Elemente programmatisch zugreifen zu k nnen,
ist die Anwendung sehr flexibel m glich.
Das Element wird in Visual Studio .NET immer mit einer Code
Behind-Datei versehen.
Sandini Bib
Modularer Code mit Benutzer-Steuerelementen 649
<table border="1">
<tr>
<td>
<a href="home.aspx">Startseite</a>
</td>
<td>
<a href="impressum.aspx">Impressum</a>
</td>
<td>
<a href="produkte.aspx">Produkte</a>
</td>
</tr>
</table>
Listing 7.1: Einfache Navigation (UserControlsNavigation.ascx)
Pr/fix und Die Direktive bestimmt mit dem Attribut TagPrefix, welches Pr fix
Tag-Name verwendet wird. TagName definiert, wie das Tag auf dieser Seite
heißt. Ein- und derselbe Code kann also nicht nur mehrfach ver-
wendet, sondern auch verschieden benannt werden. Natrlich
muss noch die Quelle mit dem Attribut src benannt werden. Auf
der Seite selbst k nnen Sie den Baustein nun folgendermaßen ein-
bauen:
Inherits="Addison.VBNet.WebForm.UserControlsNavigation2" %>
<table border="1">
<tr>
<td id="td1" runat="server">
<asp:hyperlink id="link1" runat="server" />
</td>
<td id="td2" runat="server">
<asp:hyperlink id="link2" runat="server" />
</td>
<td id="td3" runat="server">
<asp:hyperlink id="link3" runat="server" />
</td>
</tr>
</table>
Listing 7.3: Umfangreiches Benutzer-Steuerelement mit Steuerung der Eigenschaften
(UserControlsNavigation2.ascx)
End Set
End Property
End Class
Listing 7.4: Kontrolle der Links eines Benutzer-Steuerelements
(UserControlsNavigation2.ascx.vb)
Das folgende Programm zeigt nun noch, wie der Einbau des Steu-
erelementes und dessen Nutzung erfolgt:
Das Beispiel mit der Navigation l sst sich mit dieser Technik gut
erweitern. So stehen die Zellen der Tabelle im Moment neben-
einander, ideal fr eine Navigation am oberen Rand der Seite. Soll
dieselbe Navigation links erscheinen, ist es besser, die Zellen un-
tereinander anzuordnen. Da sich der HTML-Code v llig vom be-
reits gezeigten unterscheidet, ist ein neues Benutzer-Steuerele-
ment zu entwerfen. Der VB.NET-Code, der den Zugriff auf die
Sandini Bib
656 7 Erweiterte Web Form-Programmierung
Die folgende Abbildung zeigt, wie die fertige Seite aussieht. Die
um die Navigation erleichterte Seite ist nicht nur schlanker und
bersichtlicher, sondern auch einfacher zu warten. Pnderungen
an der Navigation wirken sich automatisch an allen Stellen aus,
an denen sie verwendet wird. Dies kann auch bei kleineren Pro-
jekten erheblich Zeit sparen und die Qualit t der Seiten verbes-
sern. Durch die Trennung des Codes sind berdies auch die Pn-
derungen selbst einfacher ausfhrbar.
Aus den mit festen Links versehenen Steuerelementen lassen sich Benutzer-Steuer-
leicht universelle Elemente entwickeln. Die Tags in den bereits ge- elemente perfek-
tionieren
zeigten Beispielen sind fest codiert. Da Sie aus jedem HTML-
Element ein HTML Server-Steuerelement machen k nnen und die
Links ohnehin bereits Web Server-Steuerelemente sind, bietet sich
Sandini Bib
658 7 Erweiterte Web Form-Programmierung
eine Erweiterung der Liste ber Eigenschaften an. Hier kann ber
ein Formular die Navigation dynamisch erweitert werden, hn-
lich den pers nlichen Mens in MS Office. Tats chlich verursacht
der Einbau der erweiterten Benutzer-Steuerelemente kaum Auf-
wand. Entsprechend sind Pnderungen – auch solche tief gehen-
den wie bei der Navigation – bei geschickter Planung der Appli-
kation sehr einfach ausfhrbar. Webseiten sind dynamische
Gebilde. Der Erfolg einer Site h ngt wesentlich davon ab, wie
schnell und flexibel sich diese an ndernde Benutzergewohnhei-
ten anpassen lassen. Eine der aktuellen Entwicklungen sind so
genannte My-Sites, bei denen die Gestaltung der Seite und die
Anzahl verfgbarer Optionen an die Wnsche eines Benutzers an-
gepasst werden kann. Benutzer-Steuerelemente sind das ideale
Werkzeug dafr. Wie beim Navigationsbeispiel gezeigt, k nnen
Sie leicht jedes ver nderbare Teil der Seite damit definieren. Die
vom Benutzer w hlbaren Eigenschaften werden auch programm-
technisch als Eigenschaften abgelegt. Es ist nun m glich, jedem
Steuerelement die M glichkeit zu geben, aus der Session-ID den
aktuellen Benutzer zu ermitteln und »sich selbst« so einzustellen,
wie es beispielsweise in einer Datenbank hinterlegt wurde. Der
Programmierer der Seite muss dann nicht auf die Belange der Be-
nutzer-Steuerelemente Rcksicht nehmen, sondern kann diese
wie Web Server-Steuerelemente einsetzen. Die Sammlung solcher
universeller Steuerelemente ist eine ideale Basis fr eine Biblio-
thek. Wie in Bibliotheken blich, werden nur Teile »ausgeliehen«.
In der Methode Page_Load wird dann die Ver nderung der Einstel-
lung abgefragt und die Sichtbarkeit der Navigationselemente ge-
steuert. topnav und dwnnav sind die Instanzen der Benutzer-Steu-
erelemente, settop und setdwn die Web Server-Steuerelemente, mit
denen die Anzeige gesteuert wird. Es handelt sich hierbei um die
Kontrollk stchen.
setdwn.Checked = True
End If
End Sub
End Class
Listing 7.10: Steuerung der Anzeige der Steuerelement (UserControlsHome4.aspx.vb)
Mit diesem Kontrollk stchen kann ein zus tzlicher Link aktiviert
werden. In der Code-Datei UserControlsHome4.aspx.vb wird – ge-
genber dem letzten Beispiel – Folgendes erg nzt:
If (setadm.Checked) Then
topnav.nav_link4 = True
dwnnav.nav_link4 = True
Else
topnav.nav_link4 = False
dwnnav.nav_link4 = False
End If
Sandini Bib
662 7 Erweiterte Web Form-Programmierung
Die Abbildung zeigt den Effekt, wenn der zus tzliche Link einge-
schaltet ist:
Der Internet Explorer verfgt ber eine ganze Reihe von Funktio-
nen, die bei der Einstellung »Uplevel« benutzt werden und die
nicht mit HTML 4.0 oder CSS 2.0 konform sind. Dies betrifft ins-
besondere:
E Das Attribut accesskey, das eine Taste zur Anwahl eines For-
mularfeldes erlaubt
E Das Attribut tabindex zur Festlegung der Reihenfolge der Fel-
der beim Durchlaufen mit der (Tab)-Taste
E Das Attribut tooltip, das ein kleines gelbes Pop-Up-Fenster er-
zeugt
<h1>Browsereigenschaften</h1>
Der Browser kennt folgende Funktionen:<br/>
<ul Runat="server" ID="Capabilities"/>
Listing 7.11: Vorbereitung der Liste (Ausschnitt aus BrowserCapabilites.aspx)
Diesem werden dann ber die Eigenschaft InnerText die Daten zu-
gewiesen und anschließend wird das fertige Tag an die <ul>-Kol-
lektion angefgt:
Capabilities.Controls.Add (HtmlListElement)
Sandini Bib
666 7 Erweiterte Web Form-Programmierung
Abbildung 7.8: Ausgabe des Programms f7r Internet Explorer 6.0 (oben) und
Netscape 6.2 (unten)
Beachten Sie, dass die Methode generell unzuverlssig ist, weil die Iden-
tifizierungszeichenkette im Browser von fachkundigen Benutzern ge-
flscht werden kann. Allerdings ist zu vermuten, dass derartige Manipu-
lationen nur dann ausgef$hrt werden, wenn der Empfang normaler
Webseiten mit vollem Funktionsumfang ohnehin nicht geplant ist.
javaapplets=true
activexcontrols=true
tagwriter=System.Web.UI.HtmlTextWriter
ecmascriptversion=1.2
msdomversion=${major}${minor}
w3cdomversion=1.0
css1=true
css2=true
xml=true
<filter with="${letters}" match="^b">
beta=true
</filter>
<filter with="${extra}" match="Crawler">
crawler=true
</filter>
</case>
...
Das erste Tag <case match=" "> erkennt die Ausgabe von
HTTP_USER_AGENT, alle folgenden Zuweisungen oder weitere Tests
von Teilmustern k nnen auch auf die erkannten Gruppen zugrei-
fen, die in Variablen vom Typ ${name} abgelegt sind.
Einsatzm;glichkeiten
Applikationen Wenn Sie Applikationen entwickeln, werden Sie verschiedene
Funktionen m glicherweise nur fr bestimmte Clients bereit stel-
len wollen. Es w re nun denkbar, ein Programm so universell zu
schreiben, dass es sich auf die Angaben der Browserbedingungen
einstellt. Wenn Sie die Datei machine.config um intelligente Muster
erweitern, k nnen Sie auch auf eigene Clients reagieren. So w re
es m glich, Außendienstmitarbeitern einen speziellen Browser zu
geben, beispielsweise unter Windows CE. Wird dieser erkannt,
schaltet die Anwendung in eine andere Darstellform um oder er-
laubt den Zugriff auf bestimmte Daten.
Sicherheit Aus Sicht der Systemsicherheit ist dies nur ein schwacher, aber
zus tzlicher Schutz und das Verfahren tr gt damit insgesamt zur
Verbesserung der Sicherheit bei.
7.4 SmartNavigation
Bislang wurde immer betont, dass die von Server-Steuerelemen-
ten erzeugten Codes HTML-konform sind und mit jedem Browser
Sandini Bib
SmartNavigation 669
Der sinnvolle Einsatz beschr nkt sich natrlich darauf, wenige In-
halte der Seite elegant auszutauschen. Wenn sich der Aufbau der
Seite nach dem Absenden des Formulars grundlegend ndert,
hilft die SmartNavigation-Funktion natrlich nicht.
Perfekt ist die Umsetzung allerdings nicht. Die Festsetzung des Fokus
funktioniert nicht, wenn der Benutzer die Felder mit der (Tab)-Taste
wechselt.
<configuration>
<system.web>
<pages SmartNavigation="true"/>
...
</system.web>
</configuration>
Die folgende Abbildung zeigt die Idee. Die linke Liste enth lt Re-
gionen der Erde. Die rechte enth lt L nder, wobei jeweils nur die
angezeigt werden, die zur ausgew hlten Region passen.
Abbildung 7.9: Die rechte Liste enth?lt L?ndernamen in Abh?ngigkeit vom Zustand der
linken.
Das setzt jedoch voraus, dass das entsprechende Feld immer mit
der Maus angew hlt wird. Nun kann es bei der Suche nach einem
Land sinnvoll sein, die linke Liste zgig zu durchbl ttern. Ver-
mutlich wird der Benutzer dann nicht die Maus verwenden, son-
dern die Liste ausw hlen und nun mit der ()-Taste die Liste
durchlaufen. Bei jedem Antippen der Taste wird das Formular ge-
sendet:
Die komplette Applikation zeigt, wie die Listen mit Daten gefllt
werden:
country.DataSource = dvCounTry
country.DataMember = "country"
country.DataTextField = "country_Text"
country.DataValueField = "country_Text"
country.DataBind()
End If
End Sub
End Class
Listing 7.15: Ereignisgesteuerte Verarbeitung der Listen (SmartNavigation.aspx.vb)
Beim Start werden zuerst die Daten aus der XML-Datei in ein
DataSet-Objekt eingelesen:
dsRegion.ReadXml(Server.MapPath("data/regions.xml"))
Wird die Seite das erste Mal aufgerufen, wird nun die Liste region
gefllt. Fr alle folgenden Formularaufrufe sorgt der Anzeige-
status (ViewSate) fr die Erhaltung des Listeninhalts, sodass die
Zuweisungen beim PostBack nicht mehr erfolgen mssen:
If Not Page.IsPostBack Then
region.DataSource = dsRegion
Die Verknpfung mit der L ndertabelle country wird ber das Feld
region_Id programmiert. Wie die Felder heißen, k nnen Sie Abbil-
dung 7.10 entnehmen. Die Anwendung sieht folgendermaßen aus:
region.DataValueField = "region_Id"
Wenn das Formular gesendet wird – zuerst durch die Wahl der
Region, ausgel st durch die AutoPostBack-Funktion – muss nun
die zweite Liste in Abh ngigkeit von der Auswahl aufgebaut wer-
den. Außerdem muss der gew hlte Status erhalten bleiben:
currentIndex = country.SelectedIndex
Da die Tabelle country, die die L ndernamen enth lt, nun gefiltert
werden muss, wird die Klasse DataView verwendet:
dvCounTry.Table = dsRegion.Tables("country")
Sandini Bib
SmartNavigation 675
Auf diese Tabelle wird ein Filter definiert, der der Auswahl der
ersten Liste entspricht:
dvCountry.RowFilter É
= String.Format ("region_Id='{0}'", É
region.SelectedItem.Value)
Damit man mit den Daten auch noch etwas anfangen kann, ist an
die Schaltfl che ein Ereignis gebunden, das die Methode Select-
Country ausl st:
Abbildung 7.11: Auswahl aus grHßeren Listen trotz AutoPostBack allein mit der Cursor-
Taste (linke Liste)
Sandini Bib
676 7 Erweiterte Web Form-Programmierung
http://msdn.microsoft.com/downloads/default.asp?url=/downloads/
samples/internet/asp_dot_net_servercontrols/webcontrols/default.asp
Einsatz Insgesamt besteht das Paket aus folgenden Steuerelementen:
E MultiPage
Dieses Element dient der berlagerten Darstellung mehrerer
Seiten im Browser, sodass zwischen den Seiten sehr schnell
umgeschaltet werden kann. Darber hinaus sind alle Seiten in
derselben aspx-Datei gespeichert.
E TabStrip
Das TabStrip-Steuerelement erm glicht die Darstellung von
Registerkarten im Browser.
E Toolbar
Dieses Steuerelement dient der Darstellung einer Leiste von
Schaltfl chen.
E TreeView
Mit Hilfe des Steuerelements kann eine hierarchische Daten-
menge in einer Baumstruktur abgebildet werden. Dies eignet
sich besonders fr die Navigation.
Bei Tests mit Netscape 6.2 erwies sich das Steuerelement TabStrip als
schwer handhabbar in Bezug auf die Reaktion auf CSS. Die Anzeige und
Nutzung der erstellten Applikation gelingt zwar, allerdings nur mit
schwer wiegenden Abstrichen am Design. Auch der Einsatz des Attribu-
tes ClientTarget="Downlevel" der @Page-Direktive brachte keinen Fort-
Sandini Bib
Zus?tzliche Steuerelemente: WebControls 1.0 677
Installationsanleitung
Damit Sie die Komponenten auch aus Visual Studio .NET verwen-
den k nnen, gehen Sie folgendermaßen vor:
Namensraum Der vollst ndige Namensraum kann wie folgt eingebunden wer-
einbinden den:
Imports Microsoft.Web.UI.WebControls
Wenn Sie eine neuere Version geladen haben, schauen Sie im GAC
GAC nach, was installiert wurde. Geben Sie dazu an der Eingabe-
aufforderung aus dem Visual Studio .NET-Paket Folgendes ein
(das »l« steht fr »list«):
gacutil -l
Suchen Sie den Eintrag in der Liste, der mit »Microsoft.Web« be-
ginnt. Die gesamte Zeile geh rt dann in das Assembly-Attribut.
Stellen Sie das Fenster der Eingabeaufforderung auf 300 Zeichen Breite
und 500 Zeilen Puffergrße ein, damit Sie die Liste einigermaßen lesbar
erhalten.
t
Durch die Wahl des Parameters des Attributes TagPrefix wird das
Pr fix festgelegt. In allen folgenden Beispielen wird, bereinstim-
mend mit der Dokumentation, »iewc« verwendet. Das Steuerele-
ment <TabStrip> wird deshalb im Quellcode der HTML-Seite
<iewc:TabStrip> geschrieben.
aber auch attraktivste, weil Sie die Art der Bedienung und die
Funktionalit t frei bestimmen k nnen. Die IE Webcontrols sind ei-
ne gute Basis fr ein solches Projekt.
Bei einem solchen Projekt sollten Sie sich zuerst ber die Funktio-
nalit t im Klaren sein. Fr die Navigation innerhalb eines Ver-
zeichnisbaumes wird eine Verzeichnisansicht ben tigt. Dann
brauchen Sie eine Auswahlm glichkeit fr Dateien und schließ-
lich ein Anzeigemodul dafr. Als Erg nzung dient noch ein Hoch-
lademodul, mit dem Dateien per HTTP auf den Server bertragen
werden.
Es ist eine gute Idee, den ersten Entwurf auf einem Blatt Papier zu
machen und sich ber die Lage und Funktion der Steuerelemente
klar zu werden. Das gewnschte Ergebnis zeigen die folgenden
Abbildungen. Die Funktionen werden ber Registerkarten aus-
gew hlt, die durch TabStrip dargestellt werden. Die Applikation
besteht nur aus einer einzigen Seite, die einzelnen Teile werden
durch MultiPage verwaltet und den Registerkarten zugeordnet.
Verzeichnis Die Auswahl des Verzeichnisses ist am bequemsten fr den Be-
ausw/hlen: nutzer, wenn er die vom Windows Explorer bekannte Baumstruk-
TreeView
tur nutzen kann. Das Steuerelement TreeView erledigt das in her-
vorragender Weise.
Toolbar Mit der Dateiliste kann dann auf die einzelnen Dateien eines Ver-
zeichnisses zugegriffen werden. Die Ausgabe erfolgt mit einem
CheckBoxList-Steuerelement. Da hier relativ viele Funktionen ben -
tigt werden (auch wenn in der Musterapplikation nicht alle ko-
diert sind), bietet sich ein Toolbar-Steuerelement zur Darstellung
von Schaltfl chen an.
Sandini Bib
Zus?tzliche Steuerelemente: WebControls 1.0 681
Abbildung 7.17: Anzeige einer Dateiliste und Funktionswahl 7ber Toolbar (rechts)
Eine der bereits fertigen Funktionen ist die Anzeige von Daten ber
eine ausgew hlte Datei. Dazu wird automatisch eine Registerkarte
weitergeschaltet, wo normaler Dateizugriff erfolgt. Der Aufbau der
Steuerelemente dieser Seite erfolgt weitgehend dynamisch.
Sandini Bib
682 7 Erweiterte Web Form-Programmierung
Hochladen von Das letzte Modul dient dem Hochladen von Dateien. Neben der
Dateien einfachen Dateibertragung besteht die M glichkeit, die Anzahl
der Dateien vorher festzulegen.
7.5.2 TabStrip
Das TabStrip-Steuerelement erstellt Registerkarten. Dabei werden
nur die Kopfelemente selbst erzeugt. Der zugeordnete Text im unte-
ren Teil der Seite ist davon nicht betroffen. Wie Sie diesen Teil mit
MultiPage fllen k nnen, wird im n chsten Abschnitt gezeigt. Die
Definition der Registerkarten sieht im Beispiel folgendermaßen aus:
Code hinterlegen Die so definierten Elemente funktionieren schon. Wenn mit der
Maus eine Registerkarte angeklickt wird, wechselt der Fokus da-
hin. Allerdings hat dies keinen praktischen Effekt, wenn nicht
Code hinterlegt wird. In der Musterapplikation wird ein Ereignis
verwendet, um die jeweils passende Seite aus MultiPage zu aktivie-
ren. Das Ereignis reagiert auf einen Wechsel des Index:
onselectedIndexChange="CentralTab_SelectedIndexChange"
lar nicht sofort gesendet. Der Zugriff auf die Registerkarte erfolgt
ber ihren Index. Im Programm wird der Name CentralTab ver-
wendet, die Eigenschaft SelectedIndex enth lt die aktuelle Aus-
wahl. Im Beispiel wird das verwendet, um sofort den Index der
passenden MultiPage-Seite zu setzen:
CentralPage.SelectedIndex = CentralTab.SelectedIndex
7.5.3 MultiPage
Viel mehr passiert auf den Seiten, die durch das Steuerelement
MultiPage verwaltet werden. Tats chlich werden mehrere, sich
berlagernde Seiten in einer einzigen aspx-Datei definiert. Zuerst
ein Ausschnitt aus der Applikation:
<iewc:MultiPage style="BORDER-TOP:medium none" É
selectedIndex="0" É
id="CentralPage" runat="server" É
BorderStyle="Solid" BorderWidth="1px" É
Height="450px" É
BackColor="#FFFFC0" Width="796px">
<iewc:PageView ID="PageList">
<!-- Inhalt von Seite 1 -->
</iewc:PageView>
<!-- Weitere Seiten -->
</iewc:MultiPage>
Listing 7.18: Definition des Steuerelements MultiPage
(Ausschnitt aus IeWebControls.aspx)
Das eigentliche Geheimnis der Seiten steckt weniger in der Defini- Wie es
tion. Tats chlich definiert MultiPage nur einen Rahmen, in den nor- funktioniert
males HTML und natrlich ASP.NET-Server-Steuerelemente ein-
gebettet werden k nnen.
Interessant ist die Navigation mit den Schaltfl chen »Next« und
»Back«, die von einer Registerkarte zur n chsten springen und am
Anfang und Ende die nicht verfgbare Richtung durch deaktivier-
te Schaltfl chen anzeigen. Selbstverst ndlich soll die Darstellung
der Seite außerdem mit den Registerkarten korrespondieren. Ein
Blick auf den Code zeigt, wie das funktioniert.
Sandini Bib
686 7 Erweiterte Web Form-Programmierung
MultiPage Schauen Sie sich zuerst die Definition der Schaltfl chen an. Dies
praktisch steuern sind Button-Steuerelemente, die mit dem entsprechenden Ereignis
verknpft sind:
<asp:Button id="Button1" É
runat="server" Text="< Back" Enabled="False" />
<asp:Button id="NextBtn2" É
runat="server" Text="Next >" OnClick="NextClick2" />
Die erste Schaltfl che ist gesperrt, weil sie auf der ersten Seite
steht und dort kein Rckschritt mehr m glich ist. Die zweite ist
mit einem OnClick-Ereignis verbunden, das durch die Ereignis-
behandlungsmethode NextClick2 bedient wird:
Die eigentliche Anzeige auf der ersten Seite erfolgt durch das
Steuerelement TreeView. Es zeigt die gesamte Verzeichnisstruktur
Ihres Webs an. Der n chste Abschnitt zeigt, wie es funktioniert.
7.5.4 TreeView
TreeView dient der Darstellung von hierarchischen Strukturen mit
Hilfe einer Baumansicht. Sie k nnen es auf drei Wegen erstellen:
Zuvor muss jedoch der Aufbau der Knoten erfolgen. Diese Funk-
tion wird nur beim ersten Start des Programms aufgerufen. Nach-
folgend werden die Daten im Anzeigestatus der Seite gehalten.
Dies sollten Sie beachten, wenn Sie diese Technik mit sehr großen
Verzeichnisstrukturen verwenden. Zwar wird beim erneuten La-
den der Seite verhindert, dass immer wieder auf den Verzeichnis-
baum zugegriffen wird, aber der Anzeigestatus, der als versteck-
tes Feld in der Seite gespeichert wird, w chst sehr schnell an. Im
Ergebnis werden die Seiten sehr groß, was zu langen Ladezeiten
fhrt und fr Benutzer m glicherweise irritierend ist. Die Page_
Load-Methode sieht nun folgendermaßen aus:
Dann wird ein neuer Knoten erzeugt – dies wird der Wurzelkno-
ten:
DirViewNode.Text = di.Name
Jetzt wird dem Baum der neue Knoten als erstes Element hinzuge-
fgt:
DirView.Nodes.Add (DirViewNode)
Wie es Hier wird nun fr jedes Verzeichnis ein Knoten erzeugt. Enth lt
funktioniert das aktuelle Verzeichnis subdir Unterverzeichnisse, wird die
Funktion rekursiv aufgerufen:
Abbildung 7.20: Das Auf- und Zuklappen der Zweige wird im Client ausgef7hrt.
Hier zeigt sich nun der Vorteil der DHTML-L sung: Das Auf-
und Zuklappen fhrt nicht zum Senden des Formulars, sondern
wird komplett im Browser ausgefhrt. Die Bbernahme der getrof-
fenen Auswahl, in Abbildung 7.20 ist dies der grau hinterlegte
Name, erfolgt ber die Ereignisbehandlungsmethode:
Wie es Das Absenden der Verzeichnisauswahl fhrt zuerst auf die Seite
funktioniert mit der Dateianzeige, in dem der Index fr Tabstrip und MultiPage
gesetzt wird. Dann wird der ausgew hlte Knoten ermittelt:
0 = vbnetwebform
0.0 = bin
0.1 = data
0.1.0 = images
0.1.1 = resources
0.1.2 = _vti_cnf
0.2 = templates
0.2.0 = img
0.2.0.0 = swf
0.2.1 = includes
0.3 = _vti_cnf
Pfad ermitteln Es besteht also die Aufgabe, aus der Angabe »0.2.0.0« den Pfad
»\vbnetwebform\templates\img\swf« zu berechnen. Dies ber-
nimmt die Methode GetCurrentPath:
Request.ApplicationPath.LastIndexOf("/")))
Dim ss As String = String.Empty
Dim i As Integer
For i = 1 To NodePath.Length
DirViewNode = DirView.GetNodeFromIndex(String.Join(".", É
Sandini Bib
Zus?tzliche Steuerelemente: WebControls 1.0 691
NodePath, 0, i))
FullPathInfo.AppendFormat("\{0}", DirViewNode.Text)
Next
Return Server.MapPath(FullPathInfo.ToString())
End Function
Listing 7.23: GetCurrentPath ermittelt aus dem TreeView-Objekt vollst?ndige Pfade
Bbergeben wird der Code des Knotens, beispielsweise »0.1«; das Wie es
TreeView-Objekt ist ffentlich sichtbar, weshalb direkt zugegriffen funktioniert
werden kann. Nun wird der »Knotenpfad« zuerst in ein Array
zerlegt:
Den Anfang des Pfades bildet der Stammpfad zu Ihrem Web, oh-
ne das Wurzelverzeichnis. Dies ist zwar eine etwas umst ndliche
Berechnung, vereinfacht aber wesentlich die Extraktion der Na-
men aus dem TreeView-Objekt:
FullPathInfo.Append (Request.ApplicationPath.Substring(0,
Request.ApplicationPath.LastIndexOf("/")))
For i = 1 To NodePath.Length
0
0.0
0.0.2
0.0.2.1
FullPathInfo.AppendFormat("\{0}", DirViewNode.Text)
Dieselbe Technik ist auch einsetzbar, wenn Sie ein Men$system mit
t TreeView aufbauen. Es ist hilfreich f$r den Benutzer, neben der Baum-
darstellung immer einen Zugriff auf den Pfad zu haben, sich also jeder-
zeit $ber die Ebene des gerade geffneten Men$s in der Struktur erkundi-
gen zu knnen.
FileListView.DataBind ()
Die Auswahl der Funktionen fr Dateien erfolgt nun ber das
Toolbar-Steuerelement. Lesen Sie dazu in Abschnitt 7.5.5, »Tool-
bar« ab Seite 699 weiter. Nachfolgend finden Sie erg nzende In-
formationen ber TreeView, die im Projekt nicht verwendet wur-
den.
Nach der Definition des Gitters mssen Sie berlegen, wie die Ge-
staltung erfolgt und wie die Elemente an Interaktion gewinnen.
Die Gestaltung kann durch Styles (CSS) und Festlegung eigener Gestaltung
Bilder fr die Knotenpunkte erfolgen. Die Bilder mssen zwei Zu-
st nde abdecken. In der Standarddarstellung erscheinen geschlos-
sene Knoten als Plus-Zeichen, offene als Minus-Zeichen. Beim
Klick darauf wechselt der Zustand. Zwei Attribute erlauben die
Angabe zus tzlicher Bilder vor dem Text, beispielsweise Ordner-
symbole:
Sie k nnen auf jeder Ebene, also sowohl in TreeView als auch Tree Vererben von
Node, Bilder definieren. Weil das recht umst ndlich werden kann, Bilddaten
<iewc:TreeNode text="<b>Hilfe</b>"></iewc:TreeNode>
<?xml version="1.0"?>
<TREENODES>
<treenode text="HauptmenL"/>
</TREENODES>
Nun liegen die Daten nicht immer in dieser Form vor. Es bietet
sich an, bestehende XML-Daten mit XSLT fr den Zweck der
Anzeige in TreeView zu transformieren. Dazu geben Sie die XSLT-
Datei mit dem Attribut TreeNodeXsltSrc an.
<country>ANGOLA</country>
....
</region>
</regions>
Listing 7.24: Ausschnitt aus der Datei data/regions.xml
Abbildung 7.22: Der Baum – direkt aus den XML-Daten aus data/regions.xml erstellt
select="concat('&lt;',name(.),'&gt;')"/>
<xsl:value-of select="text()"/>
<xsl:value-of É
select="concat('&lt;/',name(.),'&gt;')"/>
</xsl:attribute>
<xsl:for-each select="@*">
<xsl:call-template name="attributes">
<xsl:with-param name="attributenode" select="."/>
</xsl:call-template>
</xsl:for-each>
<xsl:apply-templates select="*"/>
</xsl:element>
</xsl:template>
<xsl:template name="attributes">
<xsl:param name="attributenode"/>
<xsl:element name="TreeNode">
<xsl:attribute name="Text">
<span style="font-size:10pt">
<b><xsl:value-of select="name(.)"/></b>
="<span style="color:red">
<xsl:value-of select="."/></span>"
</span>
</xsl:attribute>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
Listing 7.28: Die Transformationsdatei data/universal.xslt
Abbildung 7.23: Ausgabe einer beliebigen XML-Datei, hier web.config, mit dem
TreeView-Steuerelement
7.5.5 Toolbar
Im Projekt wurde auch ein Toolbar-Steuerelement eingesetzt. Dies
ist eine Zusammenstellung von Symbolen, die Aktionen ausl sen.
Das unterscheidet sich kaum von Bildschaltfl chen. Es wird Ihnen
allerdings einiges an Gestaltungsarbeit abgenommen. Sie mssen
auch nicht zwei Bilder fr die Reaktion auf den Klick (gedrckt
und normal) anfertigen, denn das Steuerelement simuliert den
3D-Effekt durch Ver nderung des Randes.
<iewc:ToolBar DefaultStyle="width:20px" É
runat="server" id="FileOperation">
<iewc:ToolBarButton tooltip="Neue Datei erzeugen" É
imageurl="data/images/newdoc.gif" É
id="FileNew" />
<iewc:ToolBarButton tooltip="Ausgew_hlte Dateien l1schen" É
imageurl="data/images/delete.gif" É
id="FileDelete" />
Sandini Bib
700 7 Erweiterte Web Form-Programmierung
OnButtonClick="FileOperation_Show"
Ausgew_hlte Datei:
<asp:Label Font-Bold="True" Runat="server" ID="FileName" />
<asp:PlaceHolder Runat="server" ID="FileShowBox" />
Die Methode wechselt auf die entsprechende Seite und liest dann
die Dateidaten ein. Aus den Angaben wird eine Tabelle erzeugt:
End If
FileName.Text = FileListView.SelectedItem.Value
Dim fi As FileInfo É
= New FileInfo(GetCurrentPath É
(DirView.SelectedNodeIndex) É
+ "\" + FileListView.SelectedItem.Value)
Dim t As Table = New Table()
t.Height = Unit.Percentage(50.0)
t.BorderWidth = Unit.Pixel(1)
t.BorderColor = Color.Blue
t.Rows.Add(NextRow("Erzeugt am", É
fi.CreationTime.ToLongDateString() É
+ ", " + fi.CreationTime.ToLongTimeString()))
t.Rows.Add(NextRow("Letzter Zugriff", É
fi.LastAccessTime.ToLongDateString() + ", " É
+ fi.LastAccessTime.ToLongTimeString()))
t.Rows.Add(NextRow("Letzte anderung", É
fi.LastWriteTime.ToLongDateString() + ", " É
+ fi.LastWriteTime.ToLongTimeString()))
t.Rows.Add(NextRow("Gr1ße", fi.Length.ToString()))
Dim Extension As String = fi.Extension
t.Rows.Add(NextRow("Erweiterung", Extension))
Select Case Extension
Case ".txt"
Case ".xml"
Case ".xsd"
Case ".xslt"
Case ".xsl"
Dim sr As StreamReader É
= New StreamReader(fi.FullName)
Dim cc As HtmlGenericControl É
= New HtmlGenericControl("div")
cc.Attributes("style") = "overflow:scroll; É
width:400px; height:200px"
cc.InnerText = sr.ReadToEnd()
sr.Close()
t.Rows.Add(NextRow("Inhalt", cc))
Exit Function
Case ".gif"
Case ""
Case ".png"
Dim img As System.Web.UI.WebControls.Image É
= New System.Web.UI.WebControls.Image()
img.ImageUrl = fi.FullName
t.Rows.Add(NextRow("Bild", img))
Exit Function
Case Else
t.Rows.Add(NextRow("Inhalt", "Unbekannter Dateityp"))
Exit Function
Sandini Bib
702 7 Erweiterte Web Form-Programmierung
End Select
FileShowBox.Controls.Add(t)
Return True
End Function
Listing 7.30: Ereignisbehandlungsmethode FileOperation_Show
FileName.Text = FileListView.SelectedItem.Value
Dim fi As FileInfo É
= New FileInfo (GetCurrentPath(DirView.SelectedNodeIndex) É
+ "\" + FileListView.SelectedItem.Value)
t.Rows.Add (NextRow É
("Erzeugt am", fi.CreationTime.ToLongDateString () É
+ ", " + fi.CreationTime.ToLongTimeString ()))
tr.Cells.Add(tc1)
tr.Cells.Add(tc2)
Return tr
End Function
Listing 7.31: Die Methode NextRow erzeugt eine Reihe in Abh?ngigkeit von den Daten
Durch die Angabe des Datentyps object bei der Deklaration kann
sowohl einfacher Text als auch ein beliebiges Steuerelement ange-
nommen und dann in der Zelle platziert werden. Die Unterschei-
dung wird im Code anhand des ermittelten Types ermittelt:
If text.GetType().Name.ToLower() = "string" Then
Damit Sie die Steuerelemente dynamisch, ber die Schleife, errei- FindControl
chen knnen, wird FindControl eingesetzt. Leider arbeitet diese
Methode nicht rekursiv, sondern durchsucht nur den aktuellen
Container. Deshalb stehen die Felder alle innerhalb eines als
Server-Steuerelement deklarierten <div>-Tags mit dem Namen
UploadControls. Auf diesem Wege erhalten Sie dynamischen Zu-
griff auf die Elemente.
Die Anzahl der Elemente wird ber eine Auswahlliste vom Typ
RadioButtonList gesteuert. Deren Ereignisbehandlungsmethode
schaltet die Sichtbarkeit der gewnschten Anzahl Felder ein.
Als Letztes bleibt noch die Reaktion auf den Sendevorgang selbst,
dies wird mit der Ereignisbehandlungsmethode Upload_SubmitCli
cked erledigt, die von der Sende-Schaltfl*che des Formulars aus-
gelst wird.
Unter diesem Namen erfolgt nun die Ablage mit SaveAs im aktuel-
len Pfad, bestimmt durch das TreeView-Element auf Seite eins:
File0.SaveAs (GetCurrentPath É
(DirView.SelectedNodeIndex) + "\" + FileName)
Die Nutzung dieser Technik ist interessant, wenn die bereits ent-
haltenen Steuerelemente nicht ausreichend sind, aber eine ver-
gleichbar komplexe Funktionalit*t gebraucht wird und eine mehr-
fache Verwendung mglich oder erforderlich ist.
Bevor Sie sich damit auseinander setzen, sollten Sie die Nutzung
von eingebauten Steuerelementen vollst*ndig verstanden haben.
Die Dateien zu dem hier vorgestellten Projekt finden Sie unter vbnet-
controlprojekt (Testprojekt f"r Steuerelement) bzw. vbnetcontrollib
(Definition der Steuerelemente) im Installationszweig der CD.
7.6.1 Grundlagen
Die Technik der kundenspezifischen Steuerelemente basiert auf
zwei verschiedenen Verfahren. Zum einen knnen Sie vorhandene
Steuerelemente – *hnlich wie die benutzerdefinierten – zusammen-
fassen, als Assembly kompilieren und dann eigenen oder fremden
Anwendungen bereit stellen. Das hat bereits den Vorteil, dass Sie
den Quellcode nicht weiterreichen mssen. Zum anderen knnen
Sie Steuerelemente auch vollst*ndig im Code erstellen. Das ist auf-
w*ndiger, aber auch flexibler. Der HTML-Code wird hier vollst*n-
dig vom Programm erzeugt. Auch hier wird eine Assembly erzeugt
und diese kann von anderen Entwicklern genutzt werden, um das
Steuerelement in eigene Applikationen einzubauen.
Sandini Bib
Kundenspezifische Steuerelemente (Custom Controls) 707
In beiden F*llen mssen Sie auf ein Werkzeug verzichten: Der Vi-
sual Studio .NET Designer l*sst sich zum Entwurf von kunden-
spezifischen Steuerelementen nicht einsetzen. Der Code-Editor ist
nichtsdestotrotz eine hervorragende Hilfe. Es werden deshalb ho-
he Ansprche an Ihr visuelles Vorstellungsvermgen gestellt,
wenn Sie Steuerelemente entwerfen sollen, die eine grafisch an-
spruchsvolle Ausgabe haben.
Die hier gezeigten Techniken zur Entwicklung derartiger Steuer- Visual Studio .NET
elemente basieren teilweise auf der Nutzung des Visual Studio
.NET. Natrlich lassen sich alle Beispiele auch ohne Studio nach-
vollziehen, allerdings fehlen die Vorlagen und einige Codes ms-
sen von Hand eingegeben werden.
Imports System.ComponentModel
Imports System.Web.UI
<DefaultProperty("Text"), É
ToolboxData("<{0}:WebCustomControl1 runat=server> É
</{0}:WebCustomControl1>")> É
Public Class WebCustomControl1
Inherits System.Web.UI.WebControls.WebControl
End Class
Listing 7.33: Die Vorlage f/r das die Steuerelemente-Bibliothek mit 5nderungen
(WebCustomControl1.vb)
Aber auch im »normalen« Code-Teil sind einige Besonderheiten Was im Code steht
zu finden. Es ist zu beachten, dass die Klasse von WebControl erbt.
Damit steht eine gewisse Basisfunktionalit*t zur Verfgung. Vor
allem aber werden damit die Methoden festgelegt, die fr die
Ausgabe der Werte verantwortlich sind. Die erste Methode, die
berschrieben werden soll, ist Render.
Die Klasse WebCustomControl1 definiert letztlich ein Steuerele-
ment und enth*lt bereits eine Eigenschaft Text, die schreib- und
lesbar ist, und eine Eberschreibung der Methode Render. Diese
Methode ist dafr verantwortlich, den vom Steuerelement erzeug-
ten Code auszugeben, also w*hrend der Abarbeitung dem Aus-
gabestrom zu bergeben.
Die hier verwendeten Namen stimmen exakt mit denen der fertigen Pro-
jekte auf der Buch-CD "berein. Sie k/nnen sich die Programme nat"rlich
auch von der CD laden. Es ist aber durchaus zu empfehlen, ein paar ele-
mentare Schritte selbst zu vollziehen.
Wenn Sie die Projekte von der CD verwenden, beachten Sie bitte, dass in
allen F0llen der Namensraum Addison.VBNet.Controls heißt. Dies dient
der besseren Organisation aller im Buch verwendeten Programme.
Erweiterung des Im Beispiel soll das Element nun erweitert werden. Fr den Ent-
Elements wurf wird ein neues Steuerelement erzeugt. Es wird dazu neben
der bereits vorhandenen Klasse WebCustomControl1 des Projekts
vbnetcontrollib eine weitere Klasse erzeugt und wieder von
WebControl abgeleitet. Gehen Sie folgendermaßen vor:
Imports System.ComponentModel
Imports System.Web.UI
Imports System.Web.UI.WebControls
<DefaultProperty("Text"), É
ToolboxData("<{0}:multibox runat=server></{0}:multibox>")> É
Public Class multibox
Inherits System.Web.UI.WebControls.WebControl
Get
Return _text
End Get
End Class
Listing 7.34: Erweiterung um ein zusammengesetztes Steuerelement (erster Schritt)
Wird das Projekt neu erstellt, knnen Sie das Element schon im Anwendung
HTML-Code einsetzen:
Beachten Sie, dass der Name der Klasse (MultiBox) den Namen
des Elements bestimmt. Die Registrierung der Assembly, die be-
reits im vorherigen Abschnitt mit @Register erfolgte, ist dagegen
nicht erneut erforderlich. Freilich bleibt das Pr*fix damit unver-
*ndert: »cc«.
Wenn Sie das Projekt starten, sehen Sie die Elemente bereits, aller-
dings ohne jede Funktion. Auch die Ansicht im Designer ist unbe-
friedigend, es ist n*mlich berhaupt nichts zu sehen:
Sandini Bib
716 7 Erweiterte Web Form-Programmierung
End Set
End Property
Eine wichtige Voraussetzung fr neue Steuerelemente ist die Inte- Steuerelemente in
gration in die Steuerelementehierarchie der Seite. Dies erfolgt der Hierarchie
ber eine eindeutige ID. Auch wenn Sie die Namen sorgf*ltig ver-
geben, kann ASP.NET nicht sicher feststellen, ob die Vergabe kon-
fliktfrei ist und das Steuerelement deshalb nicht verarbeiten. Um
dies sicherzustellen, gibt es eine spezielle Schnittstelle, INamingCon
tainer. Wird diese implementiert, funktioniert auch das bliche
PostBack-Verhalten auf Anhieb. Erg*nzen Sie dazu im Kopf der
Klasse Folgendes:
Diese Verknpfung von Ereignis ber ein Delegat erfolgt entwe- Umgang mit
der in der blichen Form, mit dem Schlsselwort Handles, oder Ereignissen
durch manuelles Hinzufgen des Eventhandlers. Fgen Sie zuerst
die folgende Methode ein. Damit wird nun jedes Mal, wenn die
Schaltfl*che angeklickt wird, die Methode ccButton_Click aufgeru-
fen:
Hier passiert nichts weiter als der Aufruf der Methode SetLabel,
die die Zuweisung vornimmt.
Sandini Bib
718 7 Erweiterte Web Form-Programmierung
Nun knnen Sie MultiBox schon mal testen. Erstellen Sie das Pro-
jekt neu und testen Sie es dann:
Die Reaktion ist sehr einfach: An den aktuellen Text in der TextBox
wird ein Pluszeichen angeh*ngt. Leider reicht der Wunsch nicht
aus, das Steuerelement muss die Behandlung dieses Ereignisses
lernen. Es muss n*mlich ein Weg gefunden werden, das bereits an
das Steuerelement weitergeleitete Ereignis wieder heraus-
zubekommen und mit dem externen Delegaten zu verbinden. Da-
zu erweitern Sie die Klasse MultiBox folgendermaßen:
Sandini Bib
Kundenspezifische Steuerelemente (Custom Controls) 719
Den Kern bildet die Definition eines Ereignisses, hier handelt es Die Verarbeitung
sich um das Abfangen des Mausklicks, das den Namen Click hat: externer
Ereignisse
Public Event Click As EventHandler
RaiseEvent Click(Me, e)
OnClick (e)
<DefaultProperty("Text"), É
ToolboxData("<{0}:multibox runat=server></{0}:multibox>"), É
DefaultEvent("Click")> _
Public Class multibox : Inherits WebControl
End Sub
Wenn Sie diese Fnderungen ausfhren, sollten sie den Inhalt von
SetMark_Click jetzt nach ccBox_Click kopieren und SetMark_Click
lschen.
Dieser Teil ist eine n*here Betrachtung wert. Zuerst erfolgt der Wie es
Zugriff auf Width ber die Standardeigenschaft: funktioniert
Me.Width.Value
Diese Eigenschaft gibt es, weil sie in der Basisklasse WebControl de-
finiert ist. Sie knnen eigene Eigenschaften erg*nzen, indem Sie
das mit Text gezeigte Verfahren verwenden. Im Beispiel wird nun
Folgendes definiert: Die Breite fhrt zu einer gleichm*ßigen Aus-
dehnung der Steuerelemente TextBox und Button, wobei die Auftei-
lung 50:50 ist. Die Hhe der Elemente bleibt dagegen unver*ndert.
Der Text dagegen soll am unteren Rand der durch die Angabe
Height bestimmten Hhe stehen. Dazu wird eine Stil-Eigenschaft
benutzt: margin-bottom. Durch Zuweisung an die Stil-Kollektion
fhrt der errechnete Wert zu einem Abstand der oberen Steuerele-
mente (Schaltfl*che und Textbox) zum Text, sodass der Text im-
mer exakt am unteren Rand des Panels erscheint.
Sandini Bib
722 7 Erweiterte Web Form-Programmierung
Methode Beschreibung
AddAttribute F-gt dem n2chsten erzeugten HTML-Element ein
Attribut hinzu
RenderBeginTag Beginnt ein neues HTML-Element und stellt das 7ff-
nende Tag dar, die Ausgabe erfolgt jedoch noch nicht
sofort, sodass weitere Manipulationen m7glich sind.
RenderEndTag Beendet die Erstellung eines HTML-Elementes und
stellt das schließende Tag dar, das Tag wird jedoch
noch nicht geschrieben.
Write Schreibt einfachen Text in die Ausgabe
WriteAttribute Erzeugt ein Attribut f-r ein HTML-Tag
WriteBeginTagAdd- Erzeugt ein 7ffnendes Tag und schreibt es sofort
Attribute
WriteEndTag Erzeugt ein schließendes Tag und schreibt es sofort
WriteFullBeginTag Schreibt ein 7ffnendes Tag, f-gt jedoch die schließende
spitze Klammer sofort ein
WriteLine Erzeugt einfachen Text, f-gt aber einen Zeilen-
umbruch an
Anwendungsbeispiel
Wenn Sie viel mit Schaltfl*chen arbeiten, wird Ihnen eventuell
aufgefallen sein, dass die Nutzung des Ereignisses OnClick in
JavaScript problematisch ist, denn dieses Attribut wird auch fr
die Auslsung von serverseitigen Ereignissen bentigt. Deshalb
scheidet der Einsatz von Button aus, wenn gleichzeitig eigener
JavaScript-Code eingesetzt werden soll. Das folgende Beispiel
zeigt, wie Sie ein Steuerelement mit ganz spezifischen Eigenschaf-
ten entwerfen. Praktisch realisiert werden soll Folgendes:
Sandini Bib
Kundenspezifische Steuerelemente (Custom Controls) 725
Starten Sie wie bereits im letzten Abschnitt gezeigt mit einer neuen
Klassendatei vom Typ Websteuerelement (benutzerdefiniert).
Imports System.ComponentModel
Imports System.Web.UI
Imports System.Web.UI.WebControls
Imports System.Collections.Specialized
<ParseChildren(False), _
DefaultProperty("ButtonText"), _
ToolboxData("<{0}:JsBox runat=server></{0}:JsBox>")> _
Public Class JsBox
Inherits System.Web.UI.WebControls.WebControl
Implements INamingContainer
Sandini Bib
726 7 Erweiterte Web Form-Programmierung
Me.UniqueID)
output.AddAttribute(HtmlTextWriterAttribute.Name, É
Me.UniqueID)
output.RenderBeginTag("input")
output.RenderEndTag()
output.AddAttribute(HtmlTextWriterAttribute.Value, É
ButtonText)
output.AddAttribute(HtmlTextWriterAttribute.Type, É
"Button")
output.AddAttribute("onclick", _
"javascript: if (confirm('Wirklich eintragen?'))É
{" É
+ Page.GetPostBackEventReference(Me) É
+ "}")
output.RenderBeginTag("input")
output.RenderEndTag()
End Sub
End Class
E INamingContainer
Diese Schnittstelle erlaubt den Zugriff auf den »Inhalt« des
Elements, denn das Steuerelement soll optional auch als Con-
tainer verwendet werden (<cc:JsBox>...</cc:JsBox>).
Sandini Bib
728 7 Erweiterte Web Form-Programmierung
E IPostBackEventHandler
Damit das PostBack-Ereignis verarbeitet werden kann, wird
diese Schnittstelle eingesetzt. Diese Schnittstelle wird erst im
zweiten Schritt implementiert.
E IPostBackDataHandler
Damit die Formulardaten verarbeitet werden knnen, ist diese
Schnittstelle ntig. Auch diese Schnittstelle wird erst im zwei-
ten Schritt implementiert.
Die Ausgabe Nun folgt die Definition der Methode Render. Die Steuerelemente
definieren werden hier vollst*ndig neu generiert. Es ist eine dankbare Auf-
gabe zur Ebung, hier Attribute und Stildefinitionen anzufgen.
Einige Hinweise dazu folgen im n*chsten Abschnitt 7.6.4, »Stile
und Attribute fr Steuerelemente« ab Seite 736.
c.RenderControl(output)
output.Write(Caption)
Nun wird noch eine ID vergeben, wobei einfach die ID des eige-
nen Steuerelements verwendet wird:
output.AddAttribute (HtmlTextWriterAttribute.Id, this.UniqueID)
Gleiches gilt fr den Namen, der unbedingt gebraucht wird, weil
sonst die Form-Kollektion keine Daten des Textfeldes aus dem For-
mular enth*lt:
Beachten Sie, dass Sie hier zus0tzlich zur ID des Steuerelementes eine
weitere Unterscheidung einf"hren m"ssen, wenn Sie mehr als ein Tag
erzeugen, das Formulardaten enthalten soll. Das ist sehr leicht zu be-
werkstelligen, wenn Sie einfach eine fortlaufende Nummer anh0ngen.
output.RenderEndTag ()
Der zweite Teil erzeugt nun eine ganz spezielle Schaltfl*che. Denn GetPostBack-
zus*tzlich zur Verarbeitung des Klickereignisses soll noch eine EventReference
output.AddAttribute ("onclick", É
"javascript: if (confirm('Wirklich eintragen?')) É
{ "
+ Page.GetPostBackEventReference(this) É
+ "; }")
Beim Test mit dem Framework 1.0 war Intellisense unter VB.NET nicht
in der Lage, die Events des Page-Objekts zu erkennen und bot deshalb
GetPostBackEventReference nicht an. Nach dem Kompilieren funktio-
nierte das Programm jedoch problemlos. Mit C# trat derselbe Fehler
nicht auf, vermutlich handelt es sich um einen Bug des VB.NET-Editors.
Falls der Fehler bei Ihnen auftritt, versuchen Sie sich das neueste Service
Pack zu beschaffen.
Am Ende wird auch das Tag fr die Schaltfl*che geschlossen und
beendet:
w.RenderBeginTag ("input")
w.RenderEndTag ()
Abbildung 7.38: Das Steuerelement mit der JavaScript-Box (nach Klick auf die Schalt-
flche)
Natrlich hat die Klasse noch zu wenig Funktionalit*t. Der Status Fehlende
des Textfeldes bleibt nicht erhalten und das Label-Steuerelement Funktionen
wird auch nicht gefllt. Sie mssen sich – das ist die wichtigste Er-
kenntnis bei der Steuerelementeprogrammierung – tats*chlich um
alle Einzelheiten selbst kmmern.
Bei der Definition von FieldText wird keine Speicherung in der Status erhalten
Klasse erfolgen, denn der Status soll nicht nur w*hrend der Erstel-
lung, sondern ber das Absenden des Formulars hinweg erhalten
bleiben. Deshalb erfolgt die Speicherung des Wertes im Anzeige-
status der Seite. Die Definition wird deshalb gegenber der ersten
Variante entsprechend nachfolgendem Muster erweitert:
Else
Return Nothing
End If
End Get
Set(ByVal Value As String)
ViewState("Text") = Value
End Set
End Property
Listing 7.38: Die Definition der Eigenschaft FieldText
Beachten Sie, dass Sie statt Text einen eindeutigen Namen w0hlen m"s-
sen, wenn Sie mehrere Eingabefelder speichern wollen.
PostBack Nun gilt es als N*chstes, die Formulardaten auch tats*chlich aus-
verarbeiten zuwerten. Zuerst werden die beiden noch fehlenden Schnittstellen
bekannt gemacht, um auf die Formulardaten zugreifen zu kn-
nen. Erg*nzen Sie dazu den Kopf der Klassendefinition folgender-
maßen:
nun nur noch prfen, ob sich die Daten ge*ndert haben – hier
durch Vergleich mit dem Anzeigestatus:
If Not ViewState("Text").ToString() = postData(Key) Then
ViewState("Text") = postData(Key)
End Sub
RaiseEvent Click(Me, e)
End Sub
Fertig! Damit ist das Steuerelement fast fertig. Erg*nzen Sie nun noch
den Kopf der Klasse um ein weiteres Attribut:
DefaultEvent("Click")
Kompilieren Sie das Steuerelement nun. Ein Blick auf den Desig-
ner zeigt, dass auch das Klickereignis bekannt ist. Ein Doppelklick
auf das Steuerelement erzeugt automatisch eine Ereignisbehand-
lungsmethode in WebForm2.aspx.vb. Erg*nzen Sie diese um die
hervorgehobene Zeile in der Mitte:
Ausblick Nun ist das Steuerelement fertig. Es realisiert eine flexible Kom-
bination aus einer Eberschrift, einem Eingabefeld und einer
Sicherheitsabfrage mit JavaScript. Der Zugriff auf den Inhalt ist
direkt und ber Klickereignisse mglich. Der Anzeigestatus bleibt
erhalten und harmoniert mit beliebigem Inhalt. Was fehlt, sind ge-
stalterische Elemente. Dies wurde im vorhergehenden Abschnitt
zum Steuerelement multibox bereits besprochen. Kombinieren Sie
Sandini Bib
Kundenspezifische Steuerelemente (Custom Controls) 735
Ein Blick auf den erzeugten HTML-Code zeigt, wie das neue Steu- Wie es intern
erelement mit ASP.NET harmoniert: funktioniert
<HTML>
<HEAD>
<title>WebForm2</title>
</HEAD>
<body MS_POSITIONING="GridLayout">
<h1>Eigene Steuerelemente</h1>
<form name="WebForm2" method="post" action="WebForm2.aspx"
id="WebForm2">
<input type="hidden" name="__VIEWSTATE" value="dDwtMTQ1MzYwNTQ2O
Tt0PDtsPGk8MT47aTwzPjs+O2w8dDw7bDxpPDE+Oz47bDx0PHA8cDxsPF
RleHQ7PjtsPEVpbiBlaWdlbmVzIFN0ZXVlcmVsZW1lbnQ7Pj47Pjs7Pjs+Pjt
0PHA8cDxsPFRleHQ7PjtsPEVpbiBlaWdlbmVzIFN0ZXVlcmVsZW1lbnQ
7Pj47Pjs7Pjs+Pjs+pg1MILApfeXltx0o1v0KFV1zbHY=" />
<h3>Hier anmelden:</h3>
<input value="Ein eigenes Steuerelement" type="Text" É
id="JsControl" name="JsControl" />
<input value="Eintragen" type="Button" É
onclick="javascript: if É
(confirm('Wirklich eintragen?'))
{ É
__doPostBack('JsControl',''); É
}" />
<input type="hidden" name="__EVENTTARGET" value="" />
<input type="hidden" name="__EVENTARGUMENT" value="" />
<script language="javascript">
<!--
function __doPostBack(eventTarget, eventArgument)
{
var theform = document.WebForm2;
theform.__EVENTTARGET.value = eventTarget;
theform.__EVENTARGUMENT.value = eventArgument;
theform.submit();
}
// -->
</script>
</form>
<span id="Eingabe">Ein eigenes Steuerelement</span>
</body>
</HTML>
Sandini Bib
736 7 Erweiterte Web Form-Programmierung
output.AddAttribute (HtmlTextWriterAttribute.Value, É
FieldText)
output.AddStyleAttribute É
(HtmlTextWriterStyle.BackgroundColor, "Red")
gen erzeugen, was sich gut auf die Qualit*t des erzeugten HTML
auswirkt. Freilich hilft das nicht gegen schlechten Geschmack bei
der Gestaltung. Die wichtigsten Strukturen, Aufz*hlungen oder
Klassen zeigt dieser Abschnitt.
Einheiten werden aus der Struktur Unit entnommen. Unit verfgt Einheiten
ber vier statischen Methoden, mit denen Sie entscheiden knnen,
welches Quellformat Ihre Zahlen haben:
E Parse
Durchsucht eine Zeichenkette und versucht daraus einen Zah-
lenwert zu extrahieren.
E Percentage
Erwartet eine Double-Wert und interpretiert ihn als Prozent-
wert. Dies ist dann interessant, wenn das Attribut Prozentwer-
te verarbeiten kann.
E Pixel
Erwartet einen Integer-Wert und definiert die Anzahl der Pi-
xel.
E Point
Erwartet einen Integer-Wert und definiert die Grße in Punkt.
Farben werden ebenfalls sehr oft bentigt. Sie stammen aus der Farben
Struktur Color, die in System.Drawing definiert ist:
ccTextBox.BackColor = Color.Red
Ebenso einfach ist der Umgang mit Fonts. Nutzen Sie fr Schrift- Fonts
grßen die Struktur FontUnit aus dem Namensraum System.Web.
UI.WebControls. FontUnit.Unit ergibt die Grße vom Typ Unit (siehe
oben). FontUnit.Type gibt den Schriftgrad vom Typ FontSize an.
FontSize ist eine Aufz*hlung, die Elemente mit FontSize.Large oder
FontSize.Smaller enth*lt. Alle Schriftarteigenschaften kapselt die
Klasse FontInfo. Sie enth*lt folgende typischen Eigenschaften:
Sandini Bib
738 7 Erweiterte Web Form-Programmierung
E Bold
E Italic
E Name
Dies ist der Name des prim*ren Fonts (Schriftartname).
E Names
Dies ist eine Kollektion aller Fonts, die verwendet werden dr-
fen, wobei der prim*re am Anfang steht.
E Overline
E Size
Die Grße vom Typ FontSize
E Strikeout
E Underline
Die Elemente erscheinen nun am Ende der Liste und lassen sich
per Drag&Drop auf die Entwurfsfl*che ziehen. Als Standardsym-
bol findet das Zahnrad Verwendung. Das ist sicher nicht optimal.
Die Klasse fr dieses Attribut ist im Namensraum System.Drawing Der Namensraum!
enthalten, weshalb zuvor noch folgende Zeile an den Anfang der
Datei gestellt werden muss:
Imports System.Drawing
Wenn Sie das Element nun erneut der Toolbox hinzufgen – wie
oben bereits beschrieben –, erscheint es nun mit diesem Symbol.
2 Das ist brigens die eigentliche Herausforderung. Um die Qualit*t der bri-
gen Symbole in Windows zu erreichen ist einige Erfahrung ntig. Verzwei-
feln Sie nicht, dem Autor des Buches sind auch keine brauchbaren Entwrfe
gelungen ;-).
Sandini Bib
742 7 Erweiterte Web Form-Programmierung
Wenn Sie beim Import der Assembly eine Fehlermeldung erhalten, die
t nur den Namen des Symbols nennt, stimmt der Pfad nicht. Verschieben
Sie dann die Bitmap-Datei oder passen Sie den Pfad im Attribut
ToolboxBitmap an.
Drag&Drop-Verhalten modifizieren
Im n*chsten Schritt geht es darum, das Verhalten der Steuerele-
mente bei der Verwendung der Toolbox zu verbessern. So wurde
im Beispielcode vorgeschlagen, dass als Pr*fix »cc« verwendet
wird. Außerdem soll ein Steuerelemente-Entwickler in der Lage
sein, die Gestaltung mit dem Designer vorzunehmen. Auch hier
helfen Design-Time-Attribute.
Einstellen einer Um das Pr*fix fest einzustellen, wird dieses mit dem verwendeten
Pr,fixvorgabe Namensraum verknpft. Die Information muss Bestandteil des
Manifestes werden – das ist eine Informationsmenge, die Bestand-
teil einer Assembly ist. Wie diese entsteht, muss hier nicht weiter
interessieren. Das erledigt der Compiler zuverl*ssig. Sie knnen
aber ein wenig eingreifen. Im Projekt in Visual Studio finden Sie
eine Datei AssemblyInfo.vb. Darin sind die Informationen enthal-
ten, die sp*ter das Manifest bilden.
Gffnen Sie jetzt diese Datei und fgen Sie am Anfang folgende De-
klaration hinzu:
Imports System.Web.UI
Gehen Sie nun etwas tiefer, etwa bis Zeile 11. Dort finden Sie die
<Assembly>-Attribute. Fgen Sie dort ein weiteres hinzu:
<Assembly: AssemblyTitle("ControlLibrary")>
<Assembly: AssemblyDescription("Verschiedene experimentelle
Steuerelemente")>
<Assembly: AssemblyConfiguration("")>
<Assembly: AssemblyCompany("Buennung & Krause GbR")>
Sandini Bib
Kundenspezifische Steuerelemente (Custom Controls) 743
Jetzt soll noch festgelegt werden, wie das Element bei Drag&Drop Benennung des
benannt wird. Diese Festlegung wird auch mit einem Attribut ge- Elements bei
Drag&Drop
troffen, diesmal jedoch wieder in der Klassenbibliothek selbst,
oberhalb der Definition der Klasse des betreffenden Steuerele-
ments. Tragen Sie dort Folgendes ein:
<ToolboxData ("<{0}:JsBox runat=server></{0}:JsBox>")>
Dieser Abschnitt war lediglich als Anregung f"r eigene Versuche ge-
dacht, denn es fehlt der Platz um die endlosen Optionen auch nur an-
satzweise darzustellen. Informieren Sie sich in der MSDN-Referenz un-
ter den hier gezeigten Stichworten "ber weitere M/glichkeiten.
Sandini Bib
8 Protokollnahe und
ablauforientierte
Programmierung
8.1 Schnellstart
Dieser Abschnitt gibt einen kompakten Eberblick ber das Thema
und zeigt sinnvolle Verknpfungen mit erg*nzenden und
vorbereitenden Kapiteln. Der Wegweiser in die Referenz hilft,
die passenden Seiten in der MSDN-Online-Referenz besonders
schnell zu finden.
Ein wichtiger Aspekt des Zugriffs auf das Protokoll HTTP ist au-
ßerdem die Programmierung von Cookies. Sie knnen damit In-
formationen permanent mit einem Benutzer verbinden. Abschnitt
8.5, »Cookies« ab Seite 791, enth*lt die ntigen Informationen.
Fr die gesamte Applikation ist auch der effiziente Austausch von
Daten und der verantwortungsvolle Umgang mit Ressourcen
wichtig. Mit ASP.NET knnen Sie die Zwischenspeicherung von
Daten (Caching) detailliert steuern und so jede Anwendung opti-
mieren. Abschnitt 8.7, »Optimierung des Datenverkehrs« ab Seite
809 fhrt in diese Technik ein.
In diesem Kapitel wird nur selten Code Behind eingesetzt, weil es die
zum Teil sehr kurzen Code-St"ckchen unn"tz aufbl0hen w"rde. In der
Praxis sollten Sie dennoch, wenn es geht, mit hinterlegtem Code arbei-
ten. Dieses Buch stellt insofern einen Sonderfall dar, als dass es statt ei-
nes großen viele kleine Programme pr0sentiert.
Sandini Bib
Die Welt der Standardobjekte 747
E Context
Dieses Objekt fasst die Daten des aktuellen Vorgangs, also alle
in einer Sitzung verwendeten Seiten, zusammen. Damit kn-
nen seitenbergreifende Lsungen programmiert werden, oh-
ne dass große Datenmengen in Sitzungsvariablen gespeichert
werden mssen und ohne dass auf das fortschrittliche Formu-
lar-Management verzichtet werden muss. Eine Behandlung
dieses Themas wird in Abschnitt 8.3.8, »Kontext-Handler und
Seitenreferenzierung« ab Seite 773 vorgenommen.
Das Objekt Application wird einmal beim Start der Applikation in- Instanziierung
stanziiert. Es steht dann die gesamte Laufzeit ber zur Verfgung.
Bei der Gestaltung von Web-Applikationen sollten Sie daran den-
ken, dass diese zwar prinzipiell aus einzelnen Seiten bestehen. Je-
der Benutzer lst im ersten Schritt eine Anforderung aus (Re-
quest). Es entsteht das Request-Objekt. Normalerweise wird eine
aspx-Seite aufgerufen. Damit entsteht ein Page-Objekt. Wenn auf
einer Seite weitere Elemente wie Bilder untergebracht sind, lst
der Browser nach dem Empfang der Antwort (Response) weitere
Anforderungen aus. Diese fhren aber nicht zwingend zu wei-
teren oder erneuten Seitenaufrufen. Andererseits kann ein HTML-
Frameset zum Abruf mehrerer Seiten fhren, ebenso wie der Nut-
zer beim Surfen weitere Anforderungen auslst. Der Benutzer
selbst wird – unabh*ngig von der Anzahl der Anforderungen –
innerhalb einer Sitzung als Einheit betrachtet. Es existiert fr ihn
also nur ein Session-Objekt. Alle Seiten mit externem Code zusam-
men bilden wiederum eine Applikation, die ihrerseits spezifische
Eigenschaften hat, die die Art der Verarbeitung kontrollieren. Da-
zu gehrt auch die Arbeitsweise des Zwischenspeichers des Aus-
Sandini Bib
750 8 Protokollnahe und ablauforientierte Programmierung
Die erste Methode des Objekts, Write, haben Sie bereits verwendet. Response.Write
Damit wird ein Text an den Browser ausgegeben. Statt Text kann Response.
WriteFile
auch der Inhalt einer Datei ausgegeben werden. Dazu wird Write-
File eingesetzt. Diese Methode besitzt zwei optionale Parameter,
die Startpunkt und L*nge des Textes angeben, gez*hlt in Byte aus
der Datei.
Beachten Sie, dass die Ausgabe nur sinnvoll ist, wenn der Ausgabedaten-
strom tats0chlich kontrolliert werden kann. Dazu m"sste der Code in
HTML eingebettet sein. Im Zusammenhang mit Steuerelementen ist die
Nutzung also ziemlich sinnlos. Aber nat"rlich gibt es Anwendungsf0lle,
beispielsweise bei der Auslieferung von Dateien an den Browser.
Die Ausgabe an den Browser kann prinzipiell mit zwei Methoden Response.
erfolgen. Zum einen wird jeder Text, der erzeugt wird, sofort ge- BufferOutput
sendet. Der Browser stellt diesen meist fortlaufend dar. Zum an-
deren ist die Verwendung eines Puffers mglich, der die Aus-
gaben sammelt und dann mit einem Mal zum Browser schickt.
Das Verhalten kann modifiziert werden. Sie knnen auch einen Puf-
ferspeicher verwenden, der alle Ausgaben sammelt. Erst wenn die
Seite vollst*ndig abgearbeitet wurde, werden alle Daten gesendet.
Sandini Bib
752 8 Protokollnahe und ablauforientierte Programmierung
Abbildung 8.3: Arbeitsweise des Puffers: Zeilenweise Ausgaben werden gesammelt und
am Ende als Block gesendet
Im Beispiel wurde eine kurze Pause (0,5 Sekunden) erzeugt, in- Pause mit der
dem der aktuelle Thread (Arbeitspfad des Prozesses) angehalten Threading-Klasse
Der Verzicht auf den Ausgabepuffer ist außerordentlich uneffek- Effizienz des
tiv, auch wenn zur Demonstration knstliche Pausen eingebaut Puffers
nimmt vom IIS den Timeout-Wert von 90 Sekunden fr die Abar-
beitung einer Seite. Wird innerhalb dieser Zeit das Programm
nicht fertig gestellt, wird der Prozess recycelt und der Browser
Sandini Bib
754 8 Protokollnahe und ablauforientierte Programmierung
Wenn Sie das Programm ausprobieren, wird nach Ablauf der Zeit
ein Fehlerereignis erscheinen.
Cookies werden in Abschnitt 8.5, »Cookies« ab Seite 791 behan- Die Standard-
delt. Die zu speichernden Daten werden dabei an den Browser methoden
http://www.seite.de/target.aspx?vari1=Wert1&vari2=Wert2
Dieser Link bertr*gt zwei Variablen: vari1 und vari2, die die Zei-
chenketten »Wert1« bzw. »Wert2« enthalten. Auf der Seite
target.aspx werden diese im Request-Objekt bereit gestellt.
<body>
<h2>Willkommen in unserem Buchladen</h2>
<b>Ihre Bestellung bitte:</b><br/>
<a id="link1" runat="server"/><br/>
<a id="link2" runat="server"/><br/>
<a id="link3" runat="server"/><br/>
<a id="link4" runat="server"/><br/>
<br/>
<asp:label id="result" runat="server"/>
</body>
Listing 8.4: Fbertragung von Daten per GET (RequestQuerystring.aspx)
Dies unterscheidet sich insofern von HTML, als dass hier der not-
wendige Parameter href und der Inhalt des Tags dynamisch in
der Methode Page_Load erzeugt werden. An den Browser wird fol-
gende Zeile gesendet:
Dann wird der Text zugewiesen, der als Link erscheinen soll:
Der Select-Zweig sorgt dann dafr, dass das Ergebnis an das Ele-
ment <asp:label/> bertragen wird. Die folgende Abbildung zeigt
das Ergebnis nach einem Klick auf einen Link. Beachten Sie die
Anzeige der Parameter in der Statuszeile des Browsers:
Neben den Leerzeichen werden vor allem die Zeichen & und = ko-
diert, da diese als Parametertrennzeichen bentigt werden. Die
Darstellung erfolgt in der Form %HH, wobei HH der hexadezimale
Code des Zeichens ist.
Einsatzm7glichkeiten
Zwei wichtige Header werden h*ufiger eingesetzt: Location und Location
Content-type. Beide mssen nicht von Hand erzeugt werden; dafr Content-Type
Content-Type: application/pdf
Content-Disposition: attachment; filename=Datei.pdf
Content-Description: ASP.NET-Generated Data
Pragma: no-cache
Expires: 0
8.3.4 Servervariablen
Der Browser bermittelt mit jeder Anforderung einige Informatio- Request.
nen an den Server, die in Programmen sinnvoll eingesetzt werden ServerVariables
Wichtige Server- Nicht alle Werte werden fr die praktische Programmierarbeit
variablen wirklich bentigt. Die wichtigsten sind die Folgenden:
E HTTP_REFERER
Wenn Ihre Seite durch Anklicken eines Hyperlinks auf einer
anderen Seite erreicht wurde, enth*lt diese Variable den URL
der Seite, von welcher der Nutzer kam.
E HTTP_USER_AGENT
Der Typ des Browsers wird angezeigt. Sie knnen auswerten,
welche Browser Ihre Nutzer bevorzugen, und die Gestaltung
der Seiten daran ausrichten.
E REMOTE_ADDR
Dieses Feld enth*lt die IP-Adresse, mit der der Browser die
Verbindung hergestellt hat.
E QUERY_STRING
Diese Variable enth*lt die Zeichenkette nach dem Fragezei-
chen in einem URL; dem Trennzeichen fr die Ebertragung
von Parametern zum Server.
E SCRIPT_NAME
Der virtuelle (relative) Pfad der aktuellen ASP.NET-Seite. Da-
mit knnen Sie Seiten automatisch mit sich selbst referenzie-
ren, ohne den Speicherort zu kennen.
E SERVER_NAME
Der Name des Webservers oder die IP-Adresse.
E PATH_TRANSLATED
Der physische Pfad der ASP.NET-Seite auf der Festplatte des
Webservers.
Wie der Zugriff auf die gesamte Kollektion erfolgt, zeigt das fol-
gende Beispiel:
<%
Dim sv As NameValueCollection
sv = Request.ServerVariables
Dim element As String
For Each element In sv
Response.Write ("<b>" + element + "</b> : ")
Response.Write (sv(element) + "<br />")
Next%>
Listing 8.6: Auslesen aller Servervariablen (Ausschnitt aus RequestServervariables.aspx)
Sandini Bib
Daten senden und empfangen 761
In der Praxis wird die vollst*ndige Liste nur selten bentigt. Das Servervariablen
folgende Programm zeigt, wie eine ganz bestimmte Information anwenden
Wie es Hier wird zuerst die Herkunft abgefragt, indem die Servervariable
funktioniert HTTP_REFERER ermittelt wird:
Die Ausgabe zeigt, dass der Internet Explorer sich von der Anga-
be berzeugen ließ und die Seite nicht als HTML interpretiert. Al-
lerdings gibt es einen zweiten Erkennungsmechanismus, der auf
die umschließenden <html>-Tags reagiert (die hier bewusst wegge-
lassen wurden). Insofern ist der Internet Explorer nicht vllig von
diesem Header abh*ngig. Testen Sie Ihre Applikation mit mehre-
ren Browsern, um die Reaktion kennenzulernen.
1. MIME-Version
2. Content-type
3. Content-transfer-encoding
1. Content-ID
2. Content-Desription
MIME-Version: 1.0
MIME-Version: 1.0 (produced by MetaSend Vx.x)
MIME-Version: (produced by MetaSend Vx.x) 1.0
MIME-Version: 1.(produced by MetaSend Vx.x)0
1. text
Umfasst Textdaten, die in der Regel vom Menschen gele-
sen werden. Typische Beispiel sind:
E text/html
HTML-Dateien
E text/plain
Einfacher Text ohne jede Formatierung
E text/richtext
RTF-Formatierter Text (RTF = Rich Text Format)
E text/x-vCard
vCard-Datens*tze, beispielsweise Kontaktadressen aus
Outlook.
2. application
Alle Datentypen, die nicht in die brigen Kategorien pas-
sen:
E application/excel
E application/msword
E application/pdf
E application/zip
3. image
Einfache Bilder:
E image/gif
E image/jpeg
E image/png
E image/tiff
Sandini Bib
766 8 Protokollnahe und ablauforientierte Programmierung
4. audio
Audio-Daten:
E audio/basic
E audio/midi
E audio/mpeg
5. video
Video-Daten und bewegte Bilder:
E video/quicktime
E video/x-msvideo
E video/x-sgi-movie
6. message
Weitere verschachtelte Mail- oder MIME-Nachrichten:
E message/rfc822
Eine eingefgte, weitere E-Mail-Nachricht, beispiels-
weise bei einer Weiterleitung.
E message/news
Eine Nachricht aus dem Usenet
E message/partial
Ein Teil einer Nachricht
7. multipart
Verschiedene Datentypen sind in einer Nachricht vereint:
E multipart/alternative
Gleicher oder *hnlicher Inhaltstyp
E multipart/mixed
Mehrfache Inhaltstypen
1. 7bit
7-bit Text. Es wird berhaupt nichts kodiert. Dieses Kopf-
Feld besagt, dass die Nachricht nur aus Zeichen im 7-bit-
ASCII-Code besteht und nicht mehr als 1.000 Zeichen (in-
klusive Zeilenumbrche) enth*lt.
2. 8bit
8-bit Text. Es wird berhaupt nichts kodiert. Dieses Kopf-
Feld besagt, dass die Nachricht nur aus Zeichen im 8-bit-
ASCII-Code besteht und nicht mehr als 1.000 Zeichen ent-
h*lt (inklusive Zeilenumbrche). Sie knnen nicht davon
ausgehen, dass alle Mail-Gateways diese Kodierung ver-
stehen.
3. binary
8-bit Text. Es wird berhaupt nichts kodiert. Alle Zeilen
zusammen knnen mehr als 1.000 Zeichen enthalten (in-
klusive Zeilenumbrche). Sie knnen nicht davon aus-
gehen, dass alle Mail-Gateways diese Kodierung verste-
hen.
4. quoted-printable
8-bit Text oder mehr als 1.000 Zeichen. Eine Standard-Me-
thode, die alle Zeichen in 7-bit-Code umwandelt. Diese
Methode ist besonders geeignet, um Text-Daten in 8-Bit-
ASCII-Code (beispielsweise bei Verwendung eines 8-Bit-
Zeichensatzes) zu bertragen. Quoted-printable ist we-
sentlich verl*sslicher als »8Bit» oder »binary«.
5. base64
Eine Standardmethode, die bin*re Daten in 7-Bit-ASCII
umwandelt. Base64 ist die geeignete Methode zum Ver-
senden von bin*ren Daten, beispielsweise GIF-, ZIP- oder
Word-Dateien.
Response.Redirect
Das folgende Beispiel besteht aus zwei Listings. Das erste zeigt
die Seite, die nur mit einem speziellen Link erreicht werden kann.
Dieser muss zuvor in einem Formular eingegeben werden. Ist das
nicht erfolgt, wird eine Weiterleitung eingesetzt, um zu diesem
Formular zu gelangen:
<html>
<head>
<title>Response.Redirect</title>
Sandini Bib
Daten senden und empfangen 769
</head>
<body>
Ihre Anmeldung bitte;<br/>
<form method="post" action="ResponseRedirect.aspx">
Ihr Name: <input type="text" name="name" />
<input type="Submit" value="Anmelden" />
(Tipp: Geben Sie das Wort "Demo" ein)
</form>
</body>
</html>
Listing 8.10: Formular zur Erfassung des Anmeldenamens (ResponseRegister.aspx)
Browsertyp Das folgende Beispiel zeigt, wie die Methode eingesetzt werden
kann. Die Ausfhrung wird hier anhand des Browsertyps gesteu-
ert:
Nun wird der Else-Zweig ausgefhrt und die Daten aus firstse.
aspx werden an das StringWriter-Objekt bergeben.
Sandini Bib
Daten senden und empfangen 773
Der Zugriff auf das Dateisystem soll hier nicht weiter beschrieben wer-
den. Dateioperationen dieser Art werden in Abschnitt 4.11, »Zugriff auf
das Dateisystem« ab Seite 329 genauer betrachtet.
Damit sich die Seite selbst aufruft, wurde zuvor der Seitenname
ermittelt:
Nun wurde am Anfang schon festgestellt, dass der Ablauf des Le-
benszyklus einer Seite ein in sich geschlossener Vorgang ist. Am
Ende, wenn die Seite verarbeitet und die Daten gesendet wurden,
werden alle Objekte entsorgt und der Inhalt geht verloren. Als
Speicher fr nutzerabh*ngige Zust*nde kam nur der Anzeigesta-
tus in Betracht. Sp*ter lernen Sie noch Sitzungsvariablen kennen,
die in einem eigenen Speicherbereich liegen. Außerdem k*men
als Speicher noch Cookies in Betracht, aber das ist vermutlich die
schlechteste Lsung.
Funktionsweise Das Context-Objekt ist lediglich in der Lage, den Zusammenhang
zwischen zwei Seiten und damit den in den Klassen enthaltenen
Daten zu erhalten, wenn ein innerer Seitenbergang erfolgt. Dazu
wird in der zweiten Datei eine Referenz definiert und eine Instanz
der Klasse der ersten Datei bernommen. So erhalten Sie jedoch
keine neue Instanz, sondern Zugriff auf die bereits bestehende.
Das klingt komplizierter als es ist. Ein einfaches Beispiel soll zei-
gen, wie es funktioniert.
FieldCityData = FieldCity.Text
Server.Transfer("ContextForm2.aspx")
End If
End Sub
End Class
Listing 8.15: Code-Datei des Formulars (ContextForm1.aspx.vb; Page_Load wird nicht
ben>tigt)
<h1>Formularauswertung</h1>
Folgende Daten wurden erfasst:<br/>
Name: <asp:Label Runat="server" ID="LabelName"/><br/>
Ort: <asp:Label Runat="server" ID="LabelCity"/><br/>
Listing 8.16: HTML-Teil der Antwortseite (ContextForm2.aspx)
End Class
Listing 8.17: Code-Datei der Antwortseite (ContextForm2.aspx.vb)
Wie es Der spannende Teil besteht jetzt im Zugriff auf die Klasse mit den
funktioniert gespeicherten Daten der ersten Seite. Die Seite ist noch Bestandteil
des Kontextes, denn durch die Ebertragung wurde die aktuelle
Anforderung vom Browser nicht beendet und damit besteht der
Zusammenhang mit der ersten Seite fort. Programmtechnisch
kann darauf ber die Eigenschaft Handler zugegriffen werden:
Context.Handler cf1 = CType(Context.Handler, ContextForm1)
Sandini Bib
Daten senden und empfangen 777
LabelName.Text = cf1.FieldNameData
Typische Probleme
Der Umgang damit ist nicht ganz unproblematisch. So knnen Sie PostBack
nur dann auf die Klasse zugreifen, wenn der Browser noch keine beachten
erneute Anforderung gesendet hat. Wenn Sie also auf der zweiten
Seite noch eine Best*tigung programmieren und diese vom Nut-
zer per POST senden lassen, geht der Zusammenhang endgltig
verloren, denn es entsteht ein neuer Kontext. Die Instanziierung
der Klasse gelingt nicht mehr. Freilich knnen Sie dennoch das
Formular erneut versenden, nur muss es dann andere Wege des
Zugriffs geben. Insofern ist die Zeile If Not Page.IsPostBack bereits
eine Vorbereitung darauf, denn sie sichert ab, dass keine Fehler-
meldung auftritt, wenn Sie dennoch ein Formular einbauen.
Die bisherigen Programme verwendeten Code Behind. Wenn Sie Kein Code Behind
nur mit aspx-Seiten arbeiten, funktioniert es auch, aber es gibt eini- verwendet?
Wenn Sie nun in der zweiten Seite auf die Klasse zugreifen mch-
ten, mssen Sie deren Namen kennen. Mit hinterlegtem Code ist
das einfach, da Sie den Klassennamen selbst festlegen. Sie knnen
ein Attribut der @Page-Direktive verwenden, um den internen Na-
men zu berschreiben:
Benutzer-Steuer- Nur als Erg*nzung sei hier angemerkt, dass in das Verfahren auch
elemente Benutzer-Steuerelemente einbezogen werden knnen. Die Refe-
renzierung erfolgt dann folgendermaßen:
<% @Reference control="ContextForm2.aspx" %>
Kontext-bezogener Datenaustausch
Wenn Sie mit ffentlichen Variablen oder mhevoll zu program-
mierenden Eigenschaften nicht glcklich sind, knnen Sie auch eine
fr den Datenaustausch verwendbare Kollektion innerhalb des
Context-Objekts verwenden. Folgendermaßen werden Werte darin
gespeichert:
Und mit der n*chsten Zeile holen Sie den Wert wieder heraus:
Context.Items("ContextVariable").ToString ()
Die Zeit vom Abruf der ersten Seite durch einen bestimmten Be-
nutzer bis zum Verlassen der Domain wird als Sitzung (engl. Ses-
sion) bezeichnet.
8.4.1 Grundlagen
ASP.NET verfgt ber ein umfangreiches und ausgereiftes Sit- Sitzungsmana-
zungsmanagement. Vom grundlegenden Prinzip her geht es da- gement
rum, den Benutzer wiederzuerkennen, wenn er dieselbe oder eine
andere Seite der Applikation abruft. War die Wiedererkennung
erfolgreich, knnen der Sitzung Daten zugeordnet werden, die fr
den gesamten Verlauf zur Verfgung stehen sollen, ohne dass ei-
ne explizite Ebertragung von Seite zu Seite mittels URL-Query-
string oder Formularen stattfindet.
E Cookies
Die *lteste und verbreitetste Methode der Statuserhaltung ba-
siert auf Cookies1. Cookies sind kleine Datenmengen, die der
Server an den Browser sendet und die dieser meist in Form
von Textdateien speichert. Ruft der Benutzer eine neue Seite
von demselben Server ab, sendet der Browser die Informatio-
nen zurck, die dieser Server platziert hat. Wenn nun der Ser-
1 Das war sogar der ursprngliche Zweck, fr den Cookies entwickelt wur-
den. Mehr dazu finden Sie im Abschnitt 8.5, »Cookies« ab Seite 791.
Sandini Bib
780 8 Protokollnahe und ablauforientierte Programmierung
E Gemeinsame Speicherbereiche
E Interne Speicherbereiche
E Dateien
E Datenbanken
ASP.NET verwendet drei der vier mglichen Methoden. Die h*u- In-Process
figste Verwendung finden gemeinsame Speicherbereiche mit dem
IIS (In-Process). Hier werden die Variablen im Speicher abgelegt
und bei erneuten Aufrufen zur Verfgung gestellt. Diese Methode
ist sehr schnell, und mit Hilfe weiterer Maßnahmen gut skalier-
bar.
Sandini Bib
782 8 Protokollnahe und ablauforientierte Programmierung
Webserver
Applikation
SessionState Diese weitere Mglichkeit ist ein spezieller Dienst, der »Out-Of-
Process«, also außerhalb des IIS l*uft und die Verteilung ber
mehrere Server erlaubt. Dieser Dienst – SessionState – kommuni-
ziert ber TCP/IP mit anderen Webservern eines Serververbunds
und tauscht Informationen ber laufende Sitzungen aus. Alle Ser-
ver verfgen deshalb st*ndig ber dieselben aktuellen Sitzungs-
informationen. Damit ist der Einsatz schneller externer Lastvertei-
lungssysteme kein Problem. Der Dienst ist ber die Konfiguration
Sandini Bib
Sitzungen (Sessions) 783
Die dritte Mglichkeit ist eine Datenbank, vorzugsweise wird dies Datenbank nutzen
der SQL Server 2000 sein. In diesem umfangreichsten, teuersten
und leistungsf*higsten Szenario werden mehrere Webserver um
einen SQL Server gruppiert. Die Lastverteilung verteilt die Anfor-
derungen auf die Webserver, die ihrerseits Daten ber den Daten-
bankserver austauschen. Der Datenbankserver selbst nutzt natr-
lich auch den Speicher zum schnellen Zugriff auf die Daten. Die
Sitzungsinformationen werden so an einem zentralen Punkt ge-
halten und mssen ber das Netzwerk nicht repliziert werden.
ASP.NET untersttzt die Verwendung des SQL Servers direkt, in-
dem in der Konfiguration eine Verbindungszeichenfolge angege-
ben wird, die auf Server und Datenbank verweist.
E IsCookieless
Wenn die Eigenschaft True zurckgibt, werden Cookies nicht
verwendet.
E IsReadOnly
Wenn die Sitzung als Nur-Lese-Sitzung gekennzeichnet wur-
de, wird True zurckgegeben. Ist Schreiben nicht erlaubt, ist
ASP.NET in der Behandlung etwas schneller.
Sandini Bib
784 8 Protokollnahe und ablauforientierte Programmierung
E Mode
Diese Eigenschaft enth*lt einen Wert einer Aufz*hlung, der
angibt, welche Speichermethode verwendet wird. Mgliche
Werte sind Off, InProc, StateServer oder SQLServer. InProc ist
der Standardwert.
E IsNewSession
Wenn die Sitzung mit der aktuellen Anforderung erzeugt wur-
de, ist diese Eigenschaft True.
E SessionID
Diese Eigenschaft enth*lt die Session-ID.
E TimeOut
Tragen Sie hier die Anzahl Minuten ein, die eine Sitzung ohne
Aktivit*t laufen darf. Der Standardwert betr*gt 20. Lst der
Benutzer innerhalb dieser Zeit keine Anforderung aus, wird
die Session-ID verworfen und bei einer dann folgenden Anfor-
derung eine neue erzeugt.
E Abandon
Abbruch der Sitzung
E Add
Fgt ein weiteres Objekt der Kollektion hinzu. Session("Wert")
= 13 entspricht Session.Add("Wert", 13), weil in VB.NET die Kol-
lektion ber eine Standardeigenschaft verfgt.
E Clear,
Mit Clear werden alle Werte gelscht, mit RemoveAll alle Objek-
te.
Sandini Bib
Sitzungen (Sessions) 785
Im Kern geht es hier immer nur darum, ein Objekt aus der aktuel- Serialisierung
len Seite so zu speichern, dass es dem Benutzer auf der n*chsten
Seite wieder zugeordnet werden kann. Das Session-Objekt bietet
dafr eine Kollektion von gespeicherten Objekten. Die Verwen-
dung des Typs Object schr*nkt die Verwendung nicht ein – auch
ganze DataSets lassen sich speichern.
Wenn Sie eigene Klassen speichern wollen, mssen diese mit dem
Attribut <Serializable> gekennzeichnet werden. So weit die Basis-
klassen dies akzeptieren, ist das Framework in der Lage, die aus
der Klasse instanziierten Objekte komplett in eine serialisierte
Form zu berfhren und sp*ter daraus wieder zu restaurieren.
E OnStart
Diese Ereignis wird ausgelst, wenn eine neue Sitzung startet.
E OnEnd
Endet eine Sitzung, egal aus welchen Grnden, wird dieses Er-
eignis ausgelst. In den meisten F*llen drfte es sich um das
Erreichen des Zeitlimits handeln.
Sandini Bib
786 8 Protokollnahe und ablauforientierte Programmierung
<sessionState É
mode="InProc" É
stateConnectionString="tcpip=127.0.0.1:42424" É
stateNetworkTimeout="10" É
sqlConnectionString="data source=127.0.0.1;É
user id=sa;password=" É
cookieless="false" É
timeout="20"
/>
Das wichtigste Attribut ist mode. Hiermit legen Sie fest, welche Me-
thode zur Bestimmung des Ablageortes der Daten verwendet
wird:
E Off
Das Sitzungsmanagement wird abgeschaltet.
E InProc
Der Standardwert, die integrierte Verwaltung mit Sitzungs-
Cookies und der Speicherung der Werte im IIS-Prozess wird
verwendet.
E StateServer
Der SessionState-Dienst wird verwendet, um die Daten so ab-
zulegen, dass sie ber mehrere Server verteilt werden knnen.
Auch diese Methode verwendet zum Erhalt der Sitzung Coo-
kies.
E SQLServer
Wenn der SQL Server verwendet wird, bleibt zwar auch die
Sitzungserkennung mit Cookies erhalten, die Ablage der Da-
ten erfolgt nun jedoch in einer Datenbank.
timeout="30"
Denken Sie aber daran, dass es sich hier um den maximal zul*ssi-
gen Zeitraum ohne Benutzeraktivit*t handelt. Solange der Benut-
zer aktiv ist, wird die Sitzung fortgefhrt. Einen Abbruch mssten
Sie programmtechnisch mit der Methode Abandon erzwingen. Die
Frage, die Sie sich stellen mssen, lautet: »Wie lange bleibt ein ak-
tiver Benutzer auf meiner Seite, ohne eine neue Ressource anzu-
fordern?«
%systemroot%\Microsoft.NET\Framework\v1.0.3705\InstallSql-
State.sql
Drcken Sie nun (F5). Das Skript wird ausgefhrt. Die Installation Installation des
erfolgt in der neu angelegten ASPState-Datenbank, sodass Ihre b- Skripts
sqlConnectionString="data source=Name_Des_Servers; É
user id=Datenbank_Nutzer; É
password=Kennwort"
Der Umgang mit dem Session-Objekt ist unabh0ngig von der Wahl des
Speicherortes und der Methode der bertragung der Session-ID. Sie
m"ssen Ihre Programme nicht "berarbeiten, wenn Sie die Konfiguration
sp0ter 0ndern.
Praktische Anwendung
Sitzungsvariablen Das folgende Programm zeigt, wie eine Sitzungsvariable erzeugt
erzeugen und gespeichert wird:
Beachten Sie hier, dass als Methode zum Aufruf des Codes
Page_Init eingesetzt wird. Cookies sind Header-Informationen,
die vor dem Senden der Seite zusammengestellt werden mssen.
Es ist offensichtlicher, diese gleich am Anfang zu setzen – auch
wenn die Seite erst am Ende des gesamten Prozesses gesendet
wird und Sie die Header bis dahin problemlos ver*ndern knnen.
currentColor.Text = color
End Sub
</script>
<html>
<head><title>VB.NET lernen</title></head>
<body>
<h1>Sessions</h1>
Dieses Skript liest eine Sessionvariable:
<b><asp:label id="currentcolor" runat="server"/></b>
<br/>
Klicken Sie auf den Link, um wieder
auf die erste Seite zu gelangen.
<br/>
<a href="session1.aspx">Zur ersten Seite</a>
</body>
</html>
Listing 8.19: Vollstndiges Beispiel zum Abruf der Session-Variablen (Session2.aspx)
Im Gegensatz zum Senden spielt der Zeitpunkt des Abrufs der In- Sitzungsvariablen
formationen beim Empfang keine Rolle. Der Browser sendet im- auslesen
mer alle Cookies zu der Domain zurck, von der er sie empfangen
hat. Im Session-Objekt stehen diese Informationen deshalb immer
zur Verfgung. Der eigentliche Speicherort fr die Werte steht na-
trlich auch immer bereit, egal ob es sich um eine Datenbank oder
den lokalen Speicher handelt. Beachten Sie, dass Daten immer als
Objekt und in serialisierter Form gespeichert werden.
8.5 Cookies
Im Abschnitt ber Sitzungen und Applikationen wurden Cookies
implizit verwendet – zur Speicherung des Status. Cookies sind
aber auch unabh*ngig davon vielf*ltig einsetzbar.
Aus heutiger Sicht muss man sagen, dass tats*chlich eine Reihe Missbrauch
von Missbrauchsmglichkeiten bestehen, die vor allem die Privat-
sph*re des Nutzers betreffen. Eine Sicherheitslcke, die ein generel-
les Abschalten rechtfertigen wrde, sind Cookies aber definitiv
nicht.
Set-Cookie: UserName=Roger+Waters; É
path=/; É
domain=comzept.de; É
expires=Tuesday, 01-Jan-2003 00:00:01 GMT
Der neue Eintrag in der Cookiedatei wird jetzt erstellt. Die erste
Zeile nach dem Header-Namen Set-Cookie enth*lt den Namen des
Cookies und dessen Inhalt. Das Cookie wird, wenn nun Domain
und Pfadangabe stimmen, in jede Anfrage in die Kopfzeilen ein-
gebaut, die der Browser an den Server stellt. Fr jedes Verzeichnis
im Webserver knnen Sie also eigene Cookies erzeugen.
E NAME=VALUE
Dies ist der Name und Inhalt des Cookies und der einzige Pa-
rameter, der nicht optional ist. Erlaubt sind alle Zeichen außer
Kommata, Semikola und Leerzeichen. Es ist empfehlenswert,
Methoden wie Server.UrlEncode zu verwenden, wenn mit dem
Inhalt umfangreichere Daten gespeichert werden sollen.
E expires=DATE
Das Verfallsdatum definiert, bis zu welchem Zeitpunkt das
Cookie leben darf. Wird das Verfallsdatum berschritten, wird
das Cookie gelscht und nicht mehr an den Server gesendet.
Das Datum muss folgendes Format haben:
Wdy, DD-Mon-YYYY HH:MM:SS GMT
Die Darstellung basiert auf RFC 822, RFC 850, RFC 1036 und
RFC 1123. Die einzige legale Zeitzone ist GMT. Beachten Sie
die Minuszeichen als Trennzeichen im Datum – dies entspricht
Sandini Bib
Cookies 795
Wird das Attribut nicht angegeben, wird der Name des Ser-
vers (Hostname) verwendet.
E path=PATH
Das Pfad-Attribut wird verwendet, um eine Untereinheit der
URL innerhalb einer Domain angeben zu knnen. Wenn der
Domainname berprft und eine Ebereinstimmung gefunden
wurde, wird nun der Pfad verglichen. Stimmt auch der Pfad
berein, wird das Cookie mit der n*chsten Anforderung an
den Server bertragen. Der Pfad »/foo« wird als gltig angese-
hen fr »/foobar« und »/foo/bar.html«. Der Pfad »/« ist ein
genereller Platzhalter. Wird kein Pfad angegeben, wird der
Pfad der aufgerufenen Seite angenommen.
E secure
Wenn ein Cookie mit dem Attribut secure gekennzeichnet ist,
wird es nur bertragen, wenn die Verbindung ber einen si-
cheren Kanal zustande kommt (HTTPS, das heißt HTTP ber
Sandini Bib
796 8 Protokollnahe und ablauforientierte Programmierung
Syntax der Cookie Wenn eine Ressource auf dem Server via URL angefordert wird,
HTTP Request prft der Browser den URL gegen alle Cookies und fgt der An-
Header
forderung an den Server bei Ebereinstimmung Variablen-/Werte-
paare der Cookies hinzu. An dieser Stelle wird klar: Ein Server
fordert keine Cookies und liest keine Cookies, er bekommt sie
vom Browser geliefert! Die Wertepaare haben das folgende For-
mat:
Cookie: NAME1=OPAQUE_STRING1; NAME2=OPAQUE_STRING2 ...
Damit Sie in den n0chsten Beispielen den Effekt sofort sehen, ist es emp-
fehlenswert, in den Sicherheitseinstellungen des Internet Explorers, Re-
gisterkarte Datenschutz, f"r alle Cookies die Option Eingabeauf-
t
forderung zu w0hlen. Sie werden dann jedes Mal aufgefordert,
empfangene Cookies zu best0tigen. In dem dann angezeigten Dialog k/n-
nen Sie auf Details klicken, um zu sehen, was Ihr Programm tats0ch-
lich gesendet hat.
Nun wird der Wert des Cookies mit Value gesetzt. Zuletzt ist noch
das Verfallsdatum wichtig, welches mit der Eigenschaft Expires
festgelegt wird. Die Darstellung der korrekten Datumsform erle-
digt ASP.NET automatisch. Deshalb knnen hier einfach Metho-
den der Klasse DateTime verwendet werden. Now ermittelt die aktu-
elle Zeit und AddHours(2) rechnet zwei Stunden hinzu. Detaillierte
Informationen zu den Datums- und Zeitmethoden finden Sie in
Abschnitt 4.9, »Datum und Zeit« ab Seite 284. Wenn Sie im
Browser die Anzeige des Cookies forciert haben, sehen Sie folgen-
de Ausgabe in der Abbildung 8.17.
Sandini Bib
Cookies 799
Fr die praktische Nutzung ist natrlich das Auslesen auf einer
anderen Seite wichtiger. Das folgende Beispiel zeigt dies:
Die Instanziierung eines Objekts lohnt freilich nur, wenn Sie pla-
nen, mehr damit zu tun, als nur den Inhalt auszulesen.
Cookie-Kollektionen verwenden
Bislang wurde zwar von der Cookie-Kollektion gesprochen, aber
diese nicht tats*chlich verwendet, da nur ein einziges Cookie vor-
handen war. Das folgende Beispiel erzeugt eine Kollektion mit
Hilfe der Klasse HttpCookieCollection und sendet drei Cookies.
Das darauf folgende Listing stellt alle Cookies dar, die der
Browser gesendet hat.
Response.Cookies.Add(cTemp)
</body>
</html>
Listing 8.23: Auslesen aller empfangenen Cookies (RequestCookiesColl.aspx)
Diese wird dann mit einer Schleife durchlaufen, zuvor werden je-
doch die Namen extrahiert. In der Kollektion bilden die Namen die
Schlssel, deshalb kommt die Eigenschaft AllKeys zum Einsatz:
Dim CookieNames() As String = MyCookieColl.AllKeys
In der Schleife kann dann der Zugriff ber die so erhaltene Liste
der Schlssel (= Cookienamen) erfolgen:
MyCookie = MyCookieColl(CookieNames(i))
Die Ausgabe nutzt dann die Eigenschaften Name und Value des
Cookie-Objekts.
8.6 Applikationsmanagement
Das Applikationsmanagement kmmert sich um Abl*ufe, Prozes-
se und Variablen, die sich auf die gesamte Anwendung auswir-
ken, also unabh*ngig von Benutzern sind.
E BeginRequest
Dieses Ereignis wird bei jeder Anforderung zuerst ausgelst.
Hier knnen Aktionen ausgefhrt werden, die unabh*ngig
von irgendeinem anderen Teil des Programms bentigt wer-
den.
Sandini Bib
Applikationsmanagement 803
E AuthenticateRequest, AuthorizeRequest
Diese Ereignisse dienen der Behandlung der Authentifizierung
(Erkennung) bzw. Autorisierung (Rechtevergabe).
E ResolveRequestCache
Wenn der interne Zwischenspeicher verwendet wird, liefert
ASP.NET Seiten aus dem Cache aus, ohne erneut den Code
auszufhren. Dieses Ereignis wird unmittelbar vor der Pr-
fung der Gltigkeit des Zwischenspeichers aufgerufen. Es er-
laubt damit die Ausfhrung von Code unabh*ngig vom Zu-
stand des Zwischenspeichers oder seiner Verwendung.
E AcquireRequestState
An dieser Stelle werden die Sitzungsdaten rekonstruiert.
Wenn eine eigene Sitzungsverwaltung implementiert werden
soll, sollte der Code hier ausgefhrt werden.
E PreRequestHandlerExecute
Dies ist das letzte Ereignis vor der Ausfhrung der Anforde-
rung. Diese fhrt unter normalen Umst*nden und bei ein-
fachen Seitenabrufen zu einem Page-Request.
E PostRequestHandlerExecute
Dies ist das erste Ereignis nach der Ausfhrung der Anforde-
rung.
E ReleaseRequestState
In diesem Schritt werden die Sitzungsdaten aktualisiert. Fnde-
rungen daran sind nun nicht mehr mglich.
E UpdateRequestCache
Falls der Zwischenspeicher aktualisiert werden soll und dazu
spezifische Aktionen notwendig sind, kann dieses Ereignis
verwendet werden.
E EndRequest
Dies ist das letzte Ereignis, bevor die Daten an den IIS zur
Auslieferung bergeben werden. Danach werden Kopf und
Krper der Antwort gesendet.
Sandini Bib
804 8 Protokollnahe und ablauforientierte Programmierung
Abbildung 8.19: Ablauf des Aufrufes der zehn Standardereignisse einer Applikation
Ungepufferte Bei der Beantwortung einer Anfrage gibt es zwei Strategien, die
Ausgaben angeforderten Daten zu bertragen. Entweder wird der gesamte
behandeln
Inhalt gesammelt und anschließend komplett bertragen. Diese
Strategie verwendet einen Ausgabepuffer, um die Daten zu sam-
meln. Dann gilt der Ablauf, den die bereits beschriebenen Ereig-
nisse behandeln. Wird dagegen die Seite ungepuffert aufgebaut,
werden immer wieder kleinere Fragmente an den IIS zum Senden
bergeben. W*hrend die linke Seite in Abbildung 8.19 unver-
*ndert und einmalig zur Ausfhrung gelangt, funktioniert das
mit der Ausgabe nicht mehr. Deshalb gibt es zwei spezielle Ereig-
nisse:
E PreSendRequestHeaders
Dieses Ereignis wird ausgelst, bevor die Kopfzeilen gesendet
werden.
E PreSendRequestContent
Auch wenn mehrere Fragmente einer Antwort bertragen
werden, gibt es nur einen Zeitpunkt, an dem die Kopfzeilen
vollst*ndig sind. Dieses Ereignis lst aus, wenn die Header
vollst*ndig vorliegen und die Ebertragung der Inhalte be-
ginnt.
Am Ende der Ebertragung wurden die anderen Antwort-Er-
eignisse dennoch ausgelst.
Sandini Bib
Applikationsmanagement 805
E Start
Dieses Ereignis tritt auf, wenn die Applikation das erste Mal
aufgerufen wird. Dies passiert logischerweise nur ein einziges
Mal.
E End
Auch dieses Ereignis ist einmalig. Es wird beim Stoppen der
Applikation aktiv.
E Error
Wenn Fehler auftreten, k#nnen Sie diese mit diesem Ereignis
behandeln. Es ist m$chtiger als Page_Error, da alle Laufzeitfeh-
ler einer Applikation abgefangen werden k#nnen.
E Disposed
Dieses Ereignis tritt auf, wenn eine Applikation vollst$ndig
entfernt wird, beispielsweise 'ber die Managementkonsole
des IIS.
Ebenso wie bei den Sitzungen k#nnen auch Applikationen Varia- Applikations-
blen speichern. Diese stehen dann allen Benutzern zur Verf'gung. variablen
Auf einer anderen Seite kann dann auf diese Variable zugegriffen
werden:
End Sub
</script>
<HTML>
<HEAD>
<title>ApplicationGetvar</title>
</HEAD>
<body MS_POSITIONING="GridLayout">
Auf dieser Seite wird die Applikationsvariable ausgelesen:
<br>
<asp:Label Runat="server" ID="ver" />
</body>
</HTML>
Listing 8.25: Nutzung einer Applikationsvariablen (ApplicationGetvar.aspx)
Eine gute Anwendung ist ein Hitz$hler f'r Ihre Webseite. Damit
der Z$hler auch exakt arbeitet, ist es sinnvoll, 'ber die interne Ar-
beitsweise nachzudenken. Der Webserver liefert Seiten an Nutzer,
wann immer diese die Seiten anfordern. So entstehen parallel lau-
fende Prozesse. Da alle Prozesse Zeit brauchen, um ausgef'hrt zu
werden, ergibt sich m#glicherweise ein Problem. Wenn zwei Nut-
zer gleichzeitig eine Seite aufrufen, werden die Werte parallel ver-
arbeitet. Wenn der Ursprungswert der Variablen 4 ist, schreibt
Nutzer 1 mit seiner Sitzung den Wert 5 zur'ck. Bis dahin hat aber
auch Nutzer 2 die Seite gestartet, ebenfalls den Wert 4 ermittelt
und 5 zur'ckgeschrieben. Danach steht der Z$hler auf 5 und
nicht, wie es richtig w$re, auf 6. Das Application-Objekt kennt des-
halb zwei besondere Methoden, die dazu gedacht sind, andere
Prozesse vor'bergehend zu stoppen – Lock und UnLock. Diese stati-
schen Methoden stammen aus der Klasse HttpApplicationState ste-
hen unmittelbar zur Verf'gung. Die folgende Abbildung zeigt,
wie die Methoden eingesetzt werden k#nnen, um den Z$hler kor-
rekt ablaufen zu lassen.
Ende des
Start des Skriptes für
Skriptes durch User 1
USER 1 User 1 Prozessdauer Skript
Zeitachse
Start des Ende des
USER 2 Skriptes durch Prozessdauer Skript Skriptes für
User 2 User 2
Click = Application(”Count”)
Click = Click + 1
Application(”Count”) = Click
2 Die Namen sind anders als in C#, was vor allem bei der ?bernahme von
fremdem Code Schwierigkeiten bereitet. In VB.NET fehlt das Pr$fix-Teil
»On« (Session_Start statt Session_OnStart).
Sandini Bib
Optimierung des Datenverkehrs 809
Application("HitCounter") = É
Convert.ToInt32(Application("HitCounter")) + 1
Application.UnLock()
End Sub
Listing 8.26: Ereignisverarbeitung in global.asax (Ausschnitt)
Zuerst soll jedoch ein einfaches Beispiel den Effekt demonstrieren. <%@Output-
Das folgende kleine Programm gibt die aktuelle Zeit und eine pas- Cache>
sende Begr'ßung aus. Rufen Sie die Seite mehrfach ab. Sie werden
sehen, dass sich der Inhalt nur alle 30 Sekunden ver$ndert. Diese
Zeit wurde n$mlich als Speicherzeit f'r den Cache gew$hlt.
<html>
<head>
<title>CachePage</title>
</head>
<body MS_POSITIONING="GridLayout">
<h1>Cache testen</h1>
<h2>Ganzseiten-Cache</h2>
<asp:Label Runat="server" ID="DatumZeit"/>
<br/>
<asp:HyperLink Runat="server" ID="link" />
</body>
</html>
Listing 8.28: Seite, die 30 Sekunden im Cache verbleibt (CachePage.aspx)
End Class
Listing 8.29: Code-Datei zu CachePage.aspx (CachePage.aspx.vb)
Die Steuerung erfolgt hier 'ber die Direktive @OutputCache. Die Ta-
belle 10.2 in Abschnitt 10.2.5, »Die Direktive @OutputCache« ab
Seite 960 zeigt alle Optionen auf einen Blick. Die n#tigen Einstel-
lungen werden hier diskutiert.
Duration Die wichtigste Angabe beim Caching ist sicher die Zeit, die die
Seite im Cache verbleiben soll. Diese Angabe erfolgt mit dem At-
tribut Duration in Sekunden. Dies f'hrt erstmal zur Wahl aller
Speicherwege. Die Seite wird also im Webserver gespeichert und
die HTTP-Kopfzeilen werden gesendet, um Proxys und Browser
zur Mitarbeit zu bewegen.
VaryByParam Einzige Pflichtangabe außer der Zeit ist das Attribut VaryByParam.
Steht hier der Wert »none«, werden die per GET oder POST ge-
sendeten Daten nicht beachtet und trotz Lnderungen daran bleibt
die Seite im Cache. Ihre auf PostBack oder Steuerelementen mit
Anzeigestatus basierenden Applikationen werden dann m#gli-
cherweise nicht mehr richtig funktionieren. Das Attribut verhin-
dert aber nicht, dass POST-Daten 'bertragen werden. Wenn Sie
nur Formulardaten annehmen, die Anzeige des Formulars aber
nicht $ndern m#chten, kann der Einsatz sinnvoll sein. Ein anderer
Parameter ist »*« – hiermit werden alle GET- und POST-Daten be-
achtet und nach jeder Lnderungen wird die Seite im Cache erneu-
ert. Dies ist die sicherste Methode, allerdings ist der Speicher-
erfolg nicht sehr hoch. Die dritte Methode ist die gezielte
Festlegung eines Parameters, dessen Lnderungsverhalten 'ber-
wacht werden soll. Schreiben Sie VaryByParam="Selection" und Ihre
Seiten nutzen einen GET-Parameter mit diesem Namen, wird bei
einer Lnderung daran eine neue Instanz in den Cache gelegt. Die
beiden folgenden Aufrufe werden dann unterschieden:
CachePage.aspx?Selection=Home
CachePage.aspx?Selection=Impressum
Sandini Bib
Optimierung des Datenverkehrs 813
Das dritte wichtige Attribut ist Location. Damit wird der Speicher- Loaction
ort gesteuert. Die Angabe ist optional. Ohne wird der Parameter
»Any« angenommen, es werden also alle verf'gbaren Speicherorte
genutzt. Zul$ssig sind folgende Parameter:
E Any
Jeder verf'gbare Speicher wird verwendet, also ein Browser,
Proxy und Server.
E Client
Der Speicher des Browsers wird verwendet. Das geschieht un-
abh$ngig davon, ob der Browser diese Funktion unterst'tzt,
denn ASP.NET wird nur die daf'r notwendigen Kopfzeilen
senden.
E DownStream
Der Speicher des Browsers oder ein HTTP 1.1 f$higer Proxy
wird verwendet. Auch hier kann nicht gepr'ft werden, ob auf
dem ?bertragungsweg solche Proxys existieren.
E None
Die Zwischenspeicherung ist deaktiviert.
E Server
Der Ausgabespeicher befindet sich auf dem Webserver.
Ein weiteres Attribut heißt VaryByControl und dient der Kontrolle VaryByControl
der Ablage einzelner Benutzer-Steuerelement (ascx-Dateien). Es
wird im n$chsten Abschnitt beschrieben. Dar'ber hinaus kann
mit VaryByCustom der Typ des Clients 'berwacht werden. M#gli-
cherweise erstellen Sie von ein und derselben Seite mehrere Ver-
sionen f'r den Internet Explorer, Netscape und Opera. Dann k#n-
nen Sie diese Seiten getrennt im Cache halten, wenn Sie
VaryByCustom="browser" benutzen. Andere Werte als dieser bed'r-
fen einer Modifikation der Verwaltung.
End Class
Listing 8.30: Steuerung des Cache im Code (CachePageCode.aspx.vb)
Sandini Bib
Optimierung des Datenverkehrs 815
Der Zugriff auf den Cache erfolgt 'ber das Response-Objekt und
dessen Eigenschaft Cache. Diese Eigenschaft gibt ein HttpCachePoli
cy-Objekt zur'ck. Der Zugriff darauf ist beispielsweise folgender-
maßen m#glich:
Dim c As HttpCachePolicy = Response.Cache
E VaryByHeaders
Eine Kollektion der HTTP-Header (Kopfzeilen), die zur Unter-
scheidung von Seiten im Cache herangezogen werden.
E VaryByParams
Eine Kollektion der Parameter, die zur Unterscheidung von
Seiten im Cache gepr'ft werden.
Des Weiteren sind eine Vielzahl Methoden verf'gbar, von denen Methoden
hier die wichtigsten vorgestellt werden:
E SetExpired
Setzt das absolute Ablaufdatum der Seite im Cache. Benutzen
Sie die Add-Methoden der Datumsstrukturen, um das Zielda-
tum zu berechnen.
E SetCacheability
Legt die Art des Speichers fest. Dies ist ein Wert der folgenden
Aufz$hlungen:
E HttpCacheability.NoCache
Keine Speicherung auf Clientseite
E HttpCacheability.Public
Alle Speicher werden verwendet
E HttpCacheability.Private
Nur Browser, nicht jedoch auf Proxy-Servern
E HttpCacheability.Server
Nur auf dem Server
E SetLastModified
Legt das Datum f'r die Last-Modified-Kopfzeile fest. Damit
wird dem Client mitgeteilt, wann sich das Dokument das letz-
te Mal ge$ndert hat, falls dieser eine weitere eigene Speicher-
strategie verwendet.
Sandini Bib
816 8 Protokollnahe und ablauforientierte Programmierung
Imports System.Web.Caching
al.Add("Madrid")
al.Add("Londond")
al.Add("Wien")
al.Add("Oslo")
al.Add("Stockholm")
Dim cd As CacheDependency É
= New CacheDependency(Server.MapPath(Request.Path))
onRemove É
= New CacheItemRemovedCallback(AddressOf É
RemovedCallback)
Cache.Add("CityCache", al, cd, _
DateTime.Now.AddSeconds(5), _
TimeSpan.Zero, _
CacheItemPriority.Normal, onRemove)
Cache("CityCache") = al
End Sub
Das Programm nutzt intensiv das Cache-Objekt. W$hrend die Zu- Wie es
weisung zur Kollektion sicher weniger Probleme bereitet, ist ein funktioniert
Blick auf die Anwendung der Methode Add angebracht.
Sandini Bib
818 8 Protokollnahe und ablauforientierte Programmierung
Dim cd As CacheDependency
É
= New CacheDependency É
(Server.MapPath(Request.Path))
Add im Detail Die Methode Add verlangt zuerst einen Namen f'r den Speicher-
platz:
Cache.Add ("CityCache",
al,
cd,
DateTime.Now.AddSeconds(5),
Dieser Parameter kann nur dann ungleich Null sein, wenn der
vorhergehende Null ist. Die Angabe eines Zeitraumes legt fest,
wie lange das Objekt unbenutzt sein muss, damit es entfernt wird:
TimeSpan.Zero,
Es folgt noch eine Priorit$t. Wenn der Server mehr Speicher ben#-
tigt, werden unter anderem auch Cache-Objekte entfernt. Die Rei-
henfolge, in der das passiert, legt dieser Parameter fest:
CacheItemPriority.Normal,
Zuletzt wird noch ein Delegat zugewiesen, der auf eine Methode
zeigt, die das Ereignis »Objekt wurde aus dem Speicher entfernt«
behandelt. Im Beispiel wird das Objekt dann neu aufgebaut:
onRemove)
Sandini Bib
Optimierung des Datenverkehrs 819
Nun passiert Folgendes: Immer wenn das Objekt aus dem Cache
verschwindet, wird die Callback-Methode aufgerufen. Im Beispiel
passiert dort Folgendes: Zuerst wird der Speicher wieder auf-
gebaut. Dann wird die Ursache f'r das Entfernen an die Kollek-
tion angeh$ngt, sodass sie sichtbar wird. Das dient hier nur der
Demonstration.
Die Anwendung der Klasse CacheDependency ist vor allem dann Anwendung
sinnvoll, wenn Sie Elemente mit XML-Daten f'llen, wie es an vie-
len Stellen in diesem Buch gemacht wird. Wenn sich nun die Da-
ten in diesen Dateien $ndern, sollten die zwischengespeicherten
Objekte schleunigst entfernt und gegen aktuellere Kopien aus-
getauscht werden.
Sandini Bib
820 8 Protokollnahe und ablauforientierte Programmierung
Caching verwenden
Verwenden Sie das Caching, wie es zuvor beschrieben wurde.
Nutzen Sie auch den Objektspeicher mit der Klasse Cache. Beach-
ten Sie aber, dass hoher programmiertechnischer Aufwand f'r ei-
ne saubere Nutzung des Speichers den Vorteil zunichte machen
kann. Der Einsatz lohnt nur, wenn es »einfach geht«.
9.1 Schnellstart
Dieser Abschnitt gibt einen kompakten ?berblick 'ber das Thema
und zeigt sinnvolle Verkn'pfungen mit erg$nzenden und vor-
bereitenden Kapiteln. Der Wegweiser in die Referenz hilft, die pas-
senden Seiten in der MSDN-Online-Referenz besonders schnell zu
finden.
Persistierung Die Abkopplung der Daten von der Datenbank erlaubt es, diese
in XML leicht zwischen den Schichten einer Applikation zu transportie-
ren. Ebenso einfach ist eine »Persistierung« m#glich, also die Spei-
cherung in einer nichtfl'chtigen Form. Als Speicher- und Trans-
portformat wird in allen F$llen XML verwendet. Um die Art und
Weise k'mmert sich .NET intern, sodass daf'r keine umfassen-
den XML-Kenntnisse n#tig sind.
Datenquellen
ADO.NET beschr$nkt den Zugriff auf Datenquellen nicht auf den
SQL Server. Nachwievor spielt MS Access eine wichtige Rolle,
denn bei kleinen Projekten oder f'r die Ablage von selten ben#tig-
ten Daten ist der Einsatz eines teueren Datenbankservers nicht
notwendig. Dar'ber hinaus stellen viele Provider zwar den Zu-
griff auf mdb-Dateien frei, verlangen jedoch f'r den SQL Server ei-
nen teilweise happigen Aufpreis. Sie m'ssen sich also immer sehr
genau 'berlegen, ob es wirklich ein SQL Server 2000 sein muss.
Sandini Bib
Grundlagen zu ADO.NET 827
ADO.NET kennt in der Version 1.0 standardm$ßig zwei so ge- Zwei Provider in
nannte Provider, die jeweils durch ein eigenes Paket von Klassen der Version 1.0
gebildet werden:
E SqlClient
E OleDb
Mitte 2002 waren die Klassen f'r die dritte Zugriffsm#glichkeit Neu in Version 1.1
noch nicht fertig verf'gbar: ODBC. ODBC (Open DataBase Con-
nectivity) ist eine schon etwas $ltere universelle Schnittstelle zu
Datenbanken. Sie wurde von Microsoft entwickelt, hat aber auch
in anderen Welten, auch unter Unix, weite Verbreitung gefunden.
Da es weit mehr Datenbanken mit ODBC-Treibern als mit OleDb
gibt, ist ODBC noch lange nicht tot. Allerdings sollte der Einsatz
wirklich nur dann stattfinden, wenn OleDb nicht verwendbar ist,
weil die betreffende Datenbank es nicht unterst'tzt.
In diesem Buch wird auf ODBC nicht weiter eingegangen, weil ODBC
f)r die hier bevorzugt behandelten Systeme MS Access und SQL Server
2000 nicht notwendig ist. Die Anwendung bereitet aber mit dem vermit-
telten Wissen wenig Probleme.
E XxxConnection
E XxxCommand
E XxxDataReader
E XxxDataAdapter
F'r den Pr$fix »Xxx« steht in der Praxis einer der Namen
»SqlClient«, »OleDb« oder »Odbc«. Ansonsten verhalten sich die
Objekte gleichartig, zumindest soweit keine Eigenschaften ver-
wendet werden, die auf eine spezifische Datenbank beschr$nkt
sind.
Mit den Basisobjekten gelingt der Zugriff auf eine Datenbank. Die
ebenfalls bereits erw$hnte Abbildung der Datenbank – mit Struk-
tur und Daten – wird mit Hilfe eines DataSet-Objekts gebildet. Die
Darstellung auf dieser Seite ist nun bereits unabh$ngig von der
verwendeten Datenquelle.
Verwendete Namensr'ume
F'r jeden Provider gibt es einen eigenen Namensraum. Außer- Namensraum
dem sind allgemeine Klassen in einer 'bergeordneten Ebene un-
tergebracht. Sie ben#tigen auf jeden Fall folgenden Eintrag:
Imports System.Data
Imports System.Data.OleDb
F'r den Umgang mit den SQL Server wird dagegen dieser Na-
mensraum verwendet:
Imports System.Data.SqlClient
Anpassen der L$uft Ihr SQL Server lokal, tragen Sie f'r <server> »localhost« ein.
Einstellungen Der Name der Datenbank d'rfte eindeutig sein. Wenn Sie die
zum ?ben in Kapitel 5 verwendete Datenbank »Shop« verwen-
den, tragen Sie diesen Namen ein. Die folgenden Beispiele bezie-
hen sich ebenfalls darauf. Als Benutzername ist der Datenbank-
benutzer anzugeben, meist ist dies »sa« (Server Administrator).
Soweit es sich um eine ungesicherte Standardinstallation handelt,
bleibt das Kennwortfeld leer. Sie k#nnen nun entweder das Objekt
instanziieren und die Methode Open verwenden oder die Verbin-
dungszeichenfolge dem Konstruktor 'bergeben.
Imports System.Data
Imports System.Data.SqlClient
End Class
Listing 9.1: Programm zum Testen der Verbindung (SqlConnectionCheck.aspx.vb)
E Provider
Dieser Parameter bezeichnet den OleDb-Provider f'r die kon-
kret verwendete Datenbank.
E Data Source
Name der Access-Datenbank, gegebenenfalls mit vollst$ndi-
gem, physischen Pfad. Verwenden Sie Server.MapPath, um den
Pfad aus der virtuellen Angabe heraus zu ermitteln.
SQL Server F'r den Zugriff auf SQL Server 7 oder 2000 verwenden Sie folgen-
de Verbindungszeichenfolge:
E Provider
Dieser Parameter bezeichnet den OleDb-Provider f'r die kon-
kret verwendete Datenbank.
E Data Source
Der Name des SQL Servers. Je nach Verbindung muss der Na-
me vollst$ndig qualifiziert sein.
E Database
Name der Datenbank, die standardm$ßig verwendet werden
soll.
Sandini Bib
Grundlagen zu ADO.NET 835
E UID
Der Name des Datenbankbenutzers f'r die verwendete Daten-
bank. Der Standardbenutzer des SQL Servers heißt »sa«.
E PWD
Das Kennwort, wenn eines vergeben wurde.
Den OleDb-Provider f)r den SQL Server sollten Sie nur verwenden,
wenn es unbedingt notwendig ist, portierbare Anwendungen zu schrei-
ben, bei denen ein sp2terer Wechsel des Datenbankmanagementsystems
absehbar ist. Wird grunds2tzlich der SQL Server eingesetzt, ist der nati-
ve Zugriff )ber den SqlClient-Provider immer vorzuziehen. Dieser Pro-
vider nutzt das spezielle TDS-Protokoll (Tabular Data Stream) f)r die
Kommunikation mit dem SQL Server.
F'r den Zugriff auf den Indexdienst von Windows 2000 oder XP Index Server
Professional bzw. .NET-Server verwenden Sie folgende Verbin-
dungszeichenfolge:
Provider=MSIDXS; Data Source=katalogname
E Provider
Dieser Parameter bezeichnet den OleDb-Provider f'r die kon-
kret verwendete Datenbank.
E Data Source
Der Name des Katalogs, der verwendet werden soll. Der Kata-
log kann mit der Managementkonsole des Indexdienstes ange-
legt werden. Mehr Informationen zur Nutzung des Indexdiens-
tes finden Sie im Abschnitt 9.6, »Indexdienst programmieren«
ab Seite 937.
F'r den Zugriff auf den Oracle (8i oder 9i) verwenden Sie folgen- Oracle
de Verbindungszeichenfolge:
E Provider
Dieser Parameter bezeichnet den OleDb-Provider f'r die kon-
kret verwendete Datenbank.
E Data Source
Der Name des Oracle-Servers. Je nach Verbindung muss der
Name vollst$ndig qualifiziert sein.
Sandini Bib
836 9 Datenbanken und ADO.NET
E Initial Catalog
Der Name der Datenbank, die verwendet werden soll.
Imports System.Collections
Imports System.Data
Imports System.Data.OleDb
Eine M#glichkeit ist schon beim alten ASP 3.0 h$ufig verwendet
worden. Dort wurde eine Applikationsvariable angelegt, die die
Verbindungszeichenfolge enth$lt. Die Erzeugung erfolgte zum
Startzeitpunkt der Applikation, die Definition in der Datei glo-
bal.asa. Sicher ist dieses Prinzip einfach auf ASP.NET 'bertragbar,
in Analogie zum alten System wird nun die global.asax verwendet.
Informationen 'ber Applikationsvariablen finden Sie im Ab-
schnitt 8.6, »Applikationsmanagement« ab Seite 802.
lassen. Der Einbau der Eintr$ge in eines der Ereignisse, die zu Be-
ginn einer Anforderung (OnRequest) ausgel#st werden, ist wie-
derum mit einer geringen Leistungseinbuße verbunden.
value="Provider=Microsoft.Jet.OLEDB.4.0; É
Data Source={0}"/>
<add key="MDB"
value="data/Shop.mdb"/>
</appSettings>
...
Listing 9.3: Ausschnitt aus der Datei web.config mit Verbindungszeichenfolgen
Imports System.Configuration
Ein anderer Grund f'r die Nutzung der Datei web.config besteht in
der M#glichkeit, diese Werte auch dann $ndern zu k#nnen, wenn
die Applikation nur als Assembly weitergegeben wird. Kunden
bekommen dann nicht den Quelltext zu Gesicht, k#nnen aber ele-
mentarste Konfigurationen selbst vornehmen. Vor allem bei Da-
tei- und Pfadnamen ist diese M#glichkeit immer angebracht.
Verbindungsorientierte Ereignisse
Die Klassen SqlConnection und OleDbConnection kennen zwei prak- StateChange
tisch bedeutsame Ereignisse, die beim Auftreten bestimmter Zu- InfoMessage
st$nde ausgel#st werden. Zum einen kann der Wechsel des Status
von offen nach geschlossen erfasst werden. Dazu dient das Ereig-
nis StateChange. Zum anderen k#nnen Nachrichten des SQL Ser-
vers mit InfoMessage abgefangen werden. Die Ereignisbehand-
lungsmethoden sind vom Typ StateChangeEventHandler und
SqlInfoMessageEventHandler.
Die Nutzung kann bei cleverem Einsatz die Programmierung et- Nutzung
was vereinfachen. Allerdings muss man sich dar'ber im Klaren
sein, dass in ASP.NET die Ereignisverarbeitung nicht so einfach
und flexibel einsetzbar ist, wie in der WinForms-Programmie-
rung.
ConfigurationSettings.AppSettings("SqlConnection"))
AddHandler conSql.StateChange, É
New StateChangeEventHandler(AddressOf É
Verbindung_OnChange)
AddHandler conSql.InfoMessage, É
New SqlInfoMessageEventHandler(AddressOf É
Sandini Bib
840 9 Datenbanken und ADO.NET
Information_OnEvent)
conSql.Open()
commSql = New SqlCommand("PRINT 'T-SQL kennt das É
PRINT-Kommando'", conSql)
commSql.ExecuteNonQuery()
conSql.Close()
End Sub
Wie es Das Programm trennt die Reaktion auf die Ereignisse »Status-
funktioniert $nderung« und »Information« v#llig vom eigentlichen Ablauf.
Zuerst sind die zwei Ereignisbehandlungsmethoden zu definie-
ren. Dazu wird die Methode Verbindung_OnChange zur Behand-
lung der Status$nderung bestimmt:
AddHandler conSql.StateChange, É
New StateChangeEventHandler(AddressOf Verbindung_OnChange)
AddHandler conSql.InfoMessage, É
New SqlInfoMessageEventHandler(AddressOf Information_OnEvent)
Sandini Bib
Grundlagen zu ADO.NET 841
E CurrentState
Diese Eigenschaft enth$lt den neuen Status, der nach dem
Wechsel gilt.
E OriginalState
In dieser Eigenschaft finden Sie den alten Status, der vor dem
Wechsel galt.
E Message
Diese Eigenschaft enth$lt die Nachricht, die der SQL Server ge-
sendet hat. Im Fall des PRINT-Kommandos ist dies nat'rlich der
Text des Kommandos.
E Source
In dieser Eigenschaft wird die Quelle der Nachricht ausgeben.
Normalerweise ist dies der Name des Providers.
Zusammenfassung
Mit diesen Informationen k#nnen Sie nun Ihre ASP.NET-Applika-
tion mit jeder Datenbank verbinden. Im n$chsten Schritt geht es
darum, die Techniken des aktiven Zugriffs auf die Datenbank
kennen zu lernen. Auch hier bietet ADO.NET ein reichhaltiges Re-
pertoire an Klassen.
Die Ausf.hrungsmethoden
Existiert das Kommando-Objekt, kann eine Ausf'hrungsmethode
verwendet werden, um die Daten zur Datenbank zu senden und –
wenn erforderlich – Ergebnisse abzurufen. Vier Methoden stehen
zur Verf'gung:
E ExecuteNonQuery
Diese Methode sendet einen Befehl an die Datenbank, erwartet
aber kein Resultat (von einer Erfolgsmeldung abgesehen). Sie
verwenden diese mit den Befehlen DELETE, UPDATE, CREATE, DROP
usw.
E ExecuteReader
Mit dieser Methode wird normalerweise eine SELECT-Abfrage
gesendet. Als Ergebnis wird ein Objekt vom Typ DataReader (je
nach Provider als SqlDataReader oder OleDbDataReader imple-
mentiert) zur'ckgegeben. Sie finden im Abschnitt 9.2.5, »Da-
tens$tze lesen« ab Seite 846 mehr Informationen dar'ber, wie
mit diesem Objekt umgegangen werden kann.
E ExecuteScalar
Manchmal ist es ausreichend, einen einzigen Wert aus der Da-
tenbank abzurufen. Dann findet diese Methode Verwendung,
die in der ersten Reihe das erste Feld liest, unabh$ngig davon,
wie viele Daten die Abfrage ergab. Um den tats$chlich ge-
w'nschten Wert zu ermitteln, ist also normalerweise ein ent-
sprechend gestalteter SELECT-Befehl n#tig.
E ExecuteXmlReader
Diese Methode steht nur im Provider SqlClient, das heißt der
Klasse SqlCommand, zur Verf'gung. Er fragt den SQL Server ab
und erwartet die Daten im XML-Format. Zur besseren Weiter-
verarbeitung wird ein XmlReader-Objekt zur'ckgegeben. Die
Anwendung setzt voraus, dass der Befehl XML-Daten erzeugt,
wozu SELECT in Verbindung mit FOR XML zum Einsatz kommt.
Allerdings sind die SqlXml-Klassen des SQLXML 3.0–Paketes
zum SQL Server f'r derartige Aufgaben besser geeignet.
Der gesamte Vorgang besteht nur aus dem Erzeugen des Kom-
mando-Objekts und der Ausf'hrung der Methode ExecuteScalar.
Diese Methode gibt den skalaren Wert immer als varianten Typ
zur'ck, also als Object. Es ist daher notwendig (und immer m#g-
lich) in den ben#tigten Datentyp zu konvertieren. Im Fall der
?bergabe an ein Label-Steuerelement wird die Umwandlung in ei-
ne Zeichenkette ben#tigt.
Sandini Bib
Grundlagen zu ADO.NET 845
Im Vergleich dazu soll auch die Abfrage von XML-Daten gezeigt XML abfragen
werden. Der folgende Ausschnitt zeigt sowohl die Abfrage als »FOR XML AUTO«
auch den Umgang mit XmlReader:
Imports System.Data.OleDb
Try
conSql.Open()
If conSql.State = ConnectionState.Open Then
commSql = New SqlCommand("SELECT * FROM Artikel", conSql)
Dim dataReader As SqlDataReader = commSql.ExecuteReader()
While dataReader.Read()
Ausgabe.InnerHtml += dataReader.GetInt64(0).ToString() +", "
Ausgabe.InnerHtml += dataReader.GetString(1) + ", "
Ausgabe.InnerHtml += dataReader.GetDecimal(2).ToString() +
", "
Ausgabe.InnerHtml += dataReader.GetInt32(3).ToString() +
","
Ausgabe.InnerHtml += "<br />"
End While
dataReader.Close()
conSql.Close()
End If
Listing 9.9: Auslesen einer Tabelle mit dem DataReader (Ausschnitt aus dem Try-Zweig
der Datei SqlCommandExReader.aspx.vb)
Wie es Der SqlDataReader verwaltet intern eine Tabelle mit den Ergebnis-
funktioniert sen, die sequenziell durchlaufen werden kann. Der n$chste Daten-
satz wird mit Read ermittelt:
While dataReader.Read()
Die Methode Read muss vor dem ersten Abruf von Daten mindestens
einmal aufgerufen werden, da der Datensatzzeiger sich am Anfang »vor«
den Datens2tzen befindet.
In der Praxis ist der Zugriff auf die abgefragten Daten nicht im-
mer so trivial, wie es bei einem einfachen SELECT * FROM der Fall ist.
Tats$chlich bietet DataReader einiges mehr.
An dieser Stelle muss klar betont werden, dass die Ausgabe von Sequen-
zen an ein derart einfaches Steuerelement wie Label hier nur der De-
monstration und Vereinfachung dient. Die vielen leistungsf2higen Da-
t
ten-Steuerelemente in ASP.NET erlauben einen weit komfortableren
Umgang mit Daten durch das Verfahren der Datenbindung. In Ab-
schnitt 9.4, »Umgang mit Datenbanken in Visual Studio .NET« ab Seite
921 finden Sie dazu ausf)hrliche Informationen.
Sandini Bib
850 9 Datenbanken und ADO.NET
Wert Bedeutung
CloseConnection Schließt die Verbindung, wenn der DataReader
geschlossen wird
KeyInfo Informationen .ber die Spalten und den Prim'rschl.s-
sel werden zur.ckgegeben. Dies unterdr.ckt m,gli-
cherweise die Daten.
SchemaOnly Es werden nur Spalteninformationen ermittelt, aber
keine Kommandos ausgef.hrt.
SequentialAccess Spalten werden sequenziell gelesen. Das ist interes-
sant, wenn große Mengen an Bin'rdaten geholt wer-
den, die den Ergebnissatz aufbl'hen.
SingleResult Es wird nur ein Feld geholt.
SingeRow Es wird nur eine Ergebniszeile geholt.
CommandBehavior.CloseConnection or CommandBehavior.SingleRow
Der Zugriff auf die Tabelle kann auf mehreren Wegen erfolgen. Im
letzten Beispiel wurde die Spaltennummer, nullbasierend gez$hlt,
eingesetzt. Außerdem kann der Name der Spalte verwendet wer-
den; die entsprechende Methode Item muss nicht geschrieben wer-
den, da es sich um die Standardeigenschaft des Objekts handelt:
dataReader("preis")
Ergebnisinforma- Es werden Ihnen immer wieder F$lle begegnen, in denen eine pr$-
tionen dynamisch zise Vorhersage 'ber die Anzahl der Felder, deren Datentypen
ermitteln
und dem m#glicherweise vorhandenen Inhalt nicht m#glich ist.
Das folgende Beispiel zeigt, wie mit Hilfe der Implementierung
der DataReader-Klasse eine beliebige Tabelle ausgelesen wird. In
der aspx-Datei (SqlCommandExReader2.aspx) ist lediglich ein Place-
Holder-Steuerelement platziert, das nun mit einer HTML-Tabelle
gef'llt wird:
Sandini Bib
Grundlagen zu ADO.NET 851
Vergleichen Sie das auch mit den im Abschnitt 9.4, »Umgang mit
Datenbanken in Visual Studio .NET« ab Seite 921 gezeigten Daten-
Steuerelementen. Die Anwendung der Elemente Repeater oder
DataGrid erlaubt leistungsf$higere Darstellungen, dagegen ist die
»selbst gebaute« Tabelle im Detail flexibler.
Imports System.Data
Imports System.Data.SqlClient
Private t As Table
Private tr As TableRow
Private tc As TableCell
Next
t.Rows.Add(tr)
Dim field As Object
While dataReader.Read()
tr = New TableRow()
Dim j As Integer
For j = 0 To dataReader.FieldCount - 1
tc = New TableCell()
field = dataReader.GetValue(j)
tc.Text = field
tr.Cells.Add(tc)
Next
t.Rows.Add(tr)
End While
Tabelle.Controls.Add(t)
dataReader.Close()
conSql.Close()
End If
Catch e As Exception
Fehler.BackColor = Color.Red
Fehler.Text = e.Message & "<br/>" & e.StackTrace
End Try
End Sub
End Class
Listing 9.10: Ausgabe einer beliebigen Tabelle des SQL Servers in HTML
(SqlCommandExReader2.aspx.vb)
Wie es Die Abfrage der Tabelle erfolgt wieder in der bereits gezeigten
funktioniert Weise. Zus$tzlich wird bei der Ausf'hrung von ExecuteReader ein
Kommando-Parameter gesetzt, mit dem die unterliegende Verbin-
dung beim Schließen des DataReader auch geschlossen wird:
CommandBehavior.CloseConnection
t = New Table()
tr = New TableRow()
For i = 0 To dataReader.FieldCount - 1
Es wird jetzt f'r jedes Feld eine Zelle erstellt und gestaltet. Der In- GetName
halt der Zelle wird dann mit der Eigenschaft Text auf den Feld-
namen gesetzt:
tc.Text = dataReader.GetName(i).ToUpper()
Die Methode GetName gibt den Namen der angegebenen Spalte zu-
r'ck.
Nach dem Anh$ngen der Reihe an die Kollektion werden nun alle
Datens$tze durchlaufen und feldweise in Zellen ausgegeben:
While dataReader.Read()
Beliebigen Inhalt ermitteln Sie am besten mit GetValue. Diese Me- GetValue
thode gibt immer den Typ Object zur'ck:
tc.Text = field
t.Rows.Add(tr)
Tabelle.Controls.Add(t)
Die Abbildung zeigt, wie dieses Programm arbeitet, wenn die Ar-
tikel-Tabelle abgefragt wird:
Hier wird nun f'r jeden Datensatz der Abfrage ein Array vom
Typ Object erzeugt:
dataReader.GetValues (fields)
dataRows.Add(fields)
Die Umsetzung in die Tabelle kann nun mit For Each erfolgen. Da
es sich um ein Array aus Arrays handelt, sind zwei derartige
Schleifen verschachtelt.
Sandini Bib
Grundlagen zu ADO.NET 855
Die Ausgabe der Tabelle erscheint zwar kompakt, ist aber nicht Vorteil: Laufzeit-
sehr effizient, denn in der Praxis kommen viele Gestaltungseigen- verhalten
schaften, Berechnungen oder weitere Steuerelemente hinzu, so-
dass das Laufzeitverhalten ung'nstig wird. Durch die Verlage-
rung der Abfrage in ein Array k#nnen Sie die Verbindung
unabh$ngig vom Laufzeitverhalten der restlichen Applikation
schnell wieder freigeben.
Nachteilig bei der Nutzung des Object-Arrays ist der Verlust der Nachteil: Verlust
Datentypen. In diesem konkreten Fall ist das Ausgabeziel sowieso der Datentypen
Welche Methode Sie verwenden, h$ngt von der Art der Weiter-
verarbeitung und der zu erwartetenden Last ab. Gegebenenfalls
m'ssen beide Varianten programmiert und dann unter realen Be-
dingungen verglichen werden.
dataReader.GetDecimal(iPreis).ToString())
sr.AppendFormat("Nummer: {0}<hr/>", É
dataReader.GetInt32(iNummer).ToString())
End While
Ausgabe.InnerHtml += sr.ToString()
dataReader.Close()
conSql.Close()
End If
Catch e As Exception
Fehler.BackColor = Color.Red
Sandini Bib
Grundlagen zu ADO.NET 857
Fehler.Text = e.Message
End Try
End Sub
End Class
Listing 9.12: Zugriff auf Spalten Cber Spaltennamen auch an den Stellen, wo Spalten-
nummern erwartet werden (SqlCommandGetOrdinal.aspx.vb)
Diese Methode ist eher als vorbereitende Maßnahme f'r eine wei-
tere Technik zu verstehen. Wenn Sie mit dem SQL Server 2000 ar-
beiten, werden Sie sicher bemerkt haben, dass die SQL-Daten-
typen nicht denen im CTS entsprechen. Beide Typwelten sind
Sandini Bib
858 9 Datenbanken und ADO.NET
Damit k#nnen Sie nun direkt mit den Typen arbeiten, die auch
zur Definition der Tabellen verwendet werden. So kennt der
OleDb-Treiber keinen Datentyp »Money«. Die Verarbeitung als
numerischer Wert ist zwar problemlos, aber in komplexeren Pro-
grammen k#nnte der Verlust der exakten Zuordnung st#ren, weil
an anderer Stelle nicht mehr erkennbar ist, dass es sich nicht nur
um eine Zahl, sondern einen W$hrungswert handelt.
In diesem Sinne soll das Programm aus Listing 9.12 nochmals ver-
$ndert werden, diesmal im Hinblick auf die Datentypen:
Innerhalb der Schleife wird nun direkt auf die SQL Server-Daten-
typen zugegriffen:
Dim oPreis As SqlMoney = dataReader.GetSqlMoney(iPreis)
Sandini Bib
860 9 Datenbanken und ADO.NET
Die Variable oPreis ist nun »typrein«, enth$lt also den Money-Typ
des SQL-Servers, der kein Lquivalent im CTS kennt. Bei der wei-
teren Verarbeitung k#nnen Sie unabh$ngig davon die ben#tigten
Umwandlungen vornehmen. Die Typklassen sind hier ausreichend
ausgestattet, hier zur Umwandlung nach Double, damit die Forma-
tierung gelingt:
sr.AppendFormat("Preis: {0:F2}<br/>", oPreis.ToDouble())
= ConfigurationSettings.AppSettings("SqlConnection")
Try
conSql.Open()
If conSql.State = ConnectionState.Open Then
Dim sr As StringBuilder = New StringBuilder()
sr.Append("SELECT * FROM Artikel;")
sr.Append("SELECT * FROM Bestellungen;")
commSql = New SqlCommand(sr.ToString(), conSql)
Dim dataReader As SqlDataReader É
= commSql.ExecuteReader(CommandBehavior.CloseConnection)
Do
t = New Table()
t.BorderStyle = BorderStyle.Solid
t.GridLines = GridLines.Both
t.Rows.Add(HeaderRow(dataReader))
Dim dataRows As ArrayList = New ArrayList()
Dim fields() As Object
While dataReader.Read()
fields = New Object(dataReader.FieldCount) {}
dataReader.GetValues(fields)
dataRows.Add(fields)
End While
Dim row() As Object
For Each row In dataRows
t.Rows.Add(GetRow(row))
Next
Tabelle.Controls.Add(t)
Loop While dataReader.NextResult()
dataReader.Close()
conSql.Close()
End If
Catch e As Exception
Fehler.BackColor = Color.Red
Fehler.Text = e.Message & e.StackTrace
End Try
End Sub
Listing 9.14: Zugriff auf mehrere Tabellen bei Abfragen einer T-SQL-Stapel-
verarbeitungsdatei (Ausschnitt aus SqlCommandMultiReader.aspx.vb)
Die weiteren Innerhalb dieser Schleife wird dann wie bisher jede einzelne Ta-
Methoden der belle erzeugt. Das sieht etwas 'berschaubarer aus als bei den bis-
Klasse
Sandini Bib
Grundlagen zu ADO.NET 863
Mit der Methode GetRow werden dann die einzelnen Zeilen gene-
riert:
Wie es Hier erfolgt, wie bei den anderen Beispielen auch, der Abruf einer
funktioniert kompletten Tabelle:
Bei der Ausf'hrung wird der Vorgang jedoch auf die Ermittlung
des Schemas der Tabelle beschr$nkt:
dataReader = commSql.ExecuteReader(CommandBehavior.SchemaOnly)
In der aspx-Datei wurde ein DataGrid definiert. Dies ist hier die
beste Methode der Ausgabe und wird im Vorgriff auf die Daten-
Steuerelemente verwendet:
Schema.DataSource = dataReader.GetSchemaTable()
Schema.DataBind()
Abbildung 9.15: Ausgabe der kompletten Tabellendefinition als Tabelle mit DataGrid
Die spannende Frage ist nun, wie Sie diese Prozedur von
ASP.NET aus aufrufen und den Parameter 'bergeben.
<body MS_POSITIONING="GridLayout">
<h1>Kommando-Klasse</h1>
<h2>Gespeicherte Prozedur verwenden</h2>
<form runat="server">
<asp:DropDownList Runat="server" ID="ArtikelNummern" />
<asp:Button Runat="server" ID="ArtikelAuswahl" É
OnClick="ArtikelAuswahl_Click" É
Text="Daten zu dieser Artikelnummer anzeigen" />
</form>
<asp:DataGrid Runat="server" ID="Ausgabe"/>
<asp:Label Runat="server" ID="Fehler" /></div>
</body>
Listing 9.18: Steuerelemente fCr Auswahlformular und Ausgabe
(SqlCommandStoredProc.aspx)
Der erste Teil des Codes muss sich nun um das F'llen der Aus-
wahlliste k'mmern:
Handles MyBase.Load
If Not Page.IsPostBack Then
Try
conSql.Open()
If conSql.State = ConnectionState.Open Then
commSql = New SqlCommand("SELECT id FROM Artikel",
conSql)
dataReader = commSql.ExecuteReader(É
CommandBehavior.CloseConnection)
ArtikelNummern.DataSource = dataReader
ArtikelNummern.DataValueField = "id"
ArtikelNummern.DataBind()
dataReader.Close()
conSql.Close()
End If
Catch e As Exception
Fehler.BackColor = Color.Red
Fehler.Text = e.Message
End Try
End If
End Sub
'... siehe nSchstes Listing fZr fehlenden Methoden
End Class
Listing 9.19: FCllen der Auswahlliste und Initialisierung
(Ausschnitt aus SqlCommandStoredProc.aspx.vb)
Hinweise Gegen'ber der bereits gezeigten Form der Abfrage mit SqlCommand
und dem daraus entstehenden DataReader gibt es hier keine
Neuigkeiten. Lediglich die Art der Initialisierung der Verbindung
wurde ge$ndert. Die Zuweisung des Verbindungs-Objektes er-
folgt nun schon bei der Instanziierung der Klasse. Die Verbin-
dungszeichenfolge wird in der Methode Page_Init 'bernommen.
Das hat keine Bedeutung f'r den Ablauf, sondern zeigt lediglich
eine Variante, wie die elementaren Einstellungen sicher an den
Anfang des Prozesses verlegt werden.
ArtikelNummern.SelectedItem.Value.ToString())
dataReader = commSql.ExecuteReader(É
CommandBehavior.CloseConnection)
Ausgabe.DataSource = dataReader
Ausgabe.DataBind()
dataReader.Close()
conSql.Close()
End If
Catch ex As Exception
Fehler.BackColor = Color.Red
Fehler.Text = ex.Message
End Try
End Sub
Listing 9.20: Die Ereignisbehandlungsmethode (Zweiter Ausschnitt aus
SqlCommandStoredProc.aspx.vb)
commSql.CommandType = CommandType.StoredProcedure
Prozeduren sind erst dann richtig leistungsf$hig, wenn man Para- Parameter
meter 'bergeben kann. Dies erfolgt durch Hinzuf'gen der Werte bergeben
an die Kollektion Parameters:
commSql.Parameters.Add ("@ArtikelNummer", É
ArtikelNummern.SelectedItem.Value.ToString ())
Dann erfolgt die Ausf'hrung der Abfrage und es wird ein Data-
Reader zur'ckgegeben:
dataReader = commSql.ExecuteReader É
(CommandBehavior.CloseConnection)
Damit ist der ganze Vorgang auch schon beendet. Das Ergebnis
wird dem DataGrid-Steuerelement zugewiesen:
Ausgabe.DataSource = dataReader
Abbildung 9.18: ADO.NET auf einen Blick. So wirken die Basisklassen zusammen.
Um das DataSet zu verstehen, ist ein Blick auf die innere Struktur
angebracht. Alle Teile in der folgenden Abbildung manifestieren
sich in entsprechenden Klassen.
Tabellen Zentraler Bestandteil des DataSet ist eine Kollektion von Tabellen
(DataTableCollection), die jeweils durch die Klasse DataTable repr$-
sentiert werden. Das ist ein wesentlicher Unterschied zum alten
Sandini Bib
Datenverwaltung mit ADO.NET 873
Innerhalb des DataSet gibt es eine Kollektion von erweiterten Ei- Erweiterte
genschaften, erreichbar 'ber die Eigenschaft ExtendedProperties. Eigenschaften
Darin k#nnen Sie eigene Informationen speichern. Diese Eigen-
schaften haben keinen Einfluss auf das DataSet selbst. Sie k#nnen
aber Daten damit persistent machen und an andere Datensenken
'bertragen. ExtendedProperties ist vom Typ PropertyCollection,
der direkt von Hashtable erbt. In Abschnitt 4.3, »Aufz$hlungen
und Kollektionen« ab Seite 222 finden Sie Informationen 'ber den
Umgang mit derartigen Kollektionen.
Der einfachste besteht darin, die Daten direkt an ein Daten-Steuer- Daten-
element zu binden. Das wurde bereits bei einigen Beispielen ge- Steuerelemente
zeigt und wird in Abschnitt 9.4, »Umgang mit Datenbanken in Vi-
sual Studio .NET« ab Seite 921 vertieft. Unabh$ngig davon wird
diese Methode – vor allem wegen ihrer frappierenden Einfachheit –
auch schon bei den ersten Schritten mit dem DataSet gezeigt. Lassen
Sie sich davon nicht irritieren, die Details folgen sp$ter.
Des Weiteren k#nnen Sie die Daten aus dem DataSet nat'rlich im- Direkte Extraktion
mer direkt extrahieren. ?ber die Kollektionen von Reihen und
Spalten ist jeder einzelne Wert selektierbar. Die Inhalte lassen sich
dann normalen Steuerelementen zuweisen oder anderweitig ver-
Sandini Bib
874 9 Datenbanken und ADO.NET
wenden. Das setzt nat'rlich voraus, dass Sie die genaue Position
der ben#tigten Daten kennen.
DataView Ein weiterer und sehr eleganter Weg besteht in der Nutzung einer
Datenansicht, der so genannten DataView. Diese Datenansichten
beeinflussen nicht die Art der Speicherung oder den Inhalt eines
DataSet, sondern filtern, sortieren oder manipulieren die Daten
nur zum Zweck der Anzeige. Der Umgang mit DataView ist nicht
besonders schwierig, deshalb wird dieser Teil »nebenbei« im Zu-
sammenhang mit den Beispielen zum DataSet abgehandelt.
Abbildung 9.20: Nach der Auswahl eines Namens erscheinen die passenden Telefon-
nummern.
Sandini Bib
876 9 Datenbanken und ADO.NET
Der folgende Teil wird nur ausgef'hrt, wenn das Formular noch
nicht zur'ckgesendet wurde, denn nur dann muss die Auswahl-
Sandini Bib
Datenverwaltung mit ADO.NET 877
Nun wird bestimmt, dass die Optionsfelder mit der id und die
Anzeige mit name gef'llt wird. Mit der folgenden Bindung er-
scheinen die Daten im Steuerelement.
Wie an der Definition in Listing 9.21 zu sehen ist, fehlt eine Sende-
schaltfl$che. Stattdessen sorgt das Attribut AutoPostBack daf'r,
dass bei Lnderungen das Formular gesendet wird. Da nur dann
eine Aktualisierung der Anzeige erforderlich ist, wenn die Listen-
auswahl auch wirklich ge$ndert wurde, wird das Ereignis OnChan-
ge ausgewertet, basierend auf folgendem Attribut:
OnSelectedIndexChanged="Adressen_OnChange"
Der zweite Teil der Applikation besteht in der Definition der Er-
eignisbehandlungsmethode:
Public Sub Adressen_OnChange(ByVal sender As Object, É
ByVal e As System.EventArgs) _
Handles Telefon.SelectedIndexChanged
Dim dv As DataView = New DataView(ds.Tables("Telefone"))
dv.RowFilter = String.Format("aid={0}", É
Adressen.SelectedItem.Value.ToString())
Telefon.DataSource = dv
Telefon.DataMember = "Telefone"
Telefon.DataBind()
End Sub
Listing 9.23: Anzeigen der Nummern an Hand der Auswahl
(Ausschnitt aus DataSetCreateLocal.aspx.vb)
Hier wird eine DataView eingesetzt, um die passenden Daten zu se- Wie es
lektieren. Angelegt wird sie auf Basis der zweiten Tabelle, Telefone. funktioniert
Ein DataView-Objekt kann Daten filtern, hier auf Basis der Aus-
wahllistewerte, die die id-Nummern der Adressen enthalten:
dv.RowFilter = String.Format("aid={0}", É
Adressen.SelectedItem.Value.ToString ())
Sandini Bib
878 9 Datenbanken und ADO.NET
dtAdressen.Columns.Add("strasse",
Type.GetType("System.String"))
dtAdressen.Columns.Add("plz", Type.GetType("System.String"))
dtAdressen.Columns.Add("ort", Type.GetType("System.String"))
' Telefone
dtTelefone.Columns.Add("id", Type.GetType("System.Int32"))
dtTelefone.Columns.Add("aid", Type.GetType("System.Int32"))
dtTelefone.Columns.Add("nummer", Type.GetType("System.String"))
dtTelefone.Columns("nummer").Caption = "Telefonnummer"
' Referenzen
Dim pk() As DataColumn = New DataColumn(1) {}
dtAdressen.Columns("id").AutoIncrement = True
dtAdressen.Columns("id").AutoIncrementSeed = 1
dtAdressen.Columns("id").ReadOnly = True
pk(0) = dtAdressen.Columns("id")
dtAdressen.PrimaryKey = pk
dtTelefone.Columns("id").AutoIncrement = True
dtTelefone.Columns("id").AutoIncrementSeed = 1
dtTelefone.Columns("id").ReadOnly = True
pk(0) = dtTelefone.Columns("id")
dtTelefone.PrimaryKey = pk
ds.Tables.Add(dtAdressen)
ds.Tables.Add(dtTelefone)
ds.Relations.Add("AdresseTelefon", É
dtAdressen.Columns("id"), É
dtTelefone.Columns("aid"))
Return ds
End Function
tempRow = ds.Tables("Adressen").NewRow()
tempRow("name") = "Lukas Werlich"
tempRow("strasse") = "Spielallee 11"
tempRow("plz") = "89487"
tempRow("ort") = "MZnchen"
ds.Tables("Adressen").Rows.Add(tempRow)
tempTel.Add("089-9987653")
tempTel.Add("0174-9992834")
currentId = Convert.ToInt32(tempRow("id"))
For Each s In tempTel
tempRow = ds.Tables("Telefone").NewRow()
tempRow("nummer") = s
tempRow("aid") = currentId
ds.Tables("Telefone").Rows.Add(tempRow)
Next
tempTel.Clear()
End Sub
Listing 9.25: Prinzip der Hinterlegung statischer Daten (Ausschnitt aus der Code Behind-
Datei der global.asax)
DataTable Am Beispiel der Tabelle Adressen soll gezeigt werden, wie Sie eine
solche Struktur entwerfen. Zuerst wird die Tabelle selbst erzeugt:
Tats2chlich hat die Methode Add f)r Spalten, wie alle anderen Konstruk-
toren auch, viele Dberladungen, die die Angabe der Parameter erlauben.
So k=nnen Sie auch eine leere Spalte anlegen und sp2ter mit dem Namen
und verschiedenen Eigenschaften versehen. Einige Tipps dazu finden Sie
im Abschnitt 9.3.2, »Die Struktur einer Tabelle im DataSet festlegen«
ab Seite 884.
Dem ersten Element wird dann die Spalte zugeordnet, die den
Prim$rschl'ssel darstellt:
pk(0) = dtAdressen.Columns("id")
dtAdressen.PrimaryKey = pk
dtAdressen.Columns("id").AutoIncrement = True
dtAdressen.Columns("id").AutoIncrementSeed = 1
dtAdressen.Columns("id").ReadOnly = True
Sandini Bib
882 9 Datenbanken und ADO.NET
Abbildung 9.21: Der Verstoß gegen die Beziehung fChrt zu einer Ausnahme
In der Abbildung sehen Sie, dass der Fehler beim Hinzuf'gen der
Reihe zur Tabelle Telefone erzeugt wurde (der Wert »7« existierte
nicht). Schauen Sie sich nun den Code der Methode FillDataSet an,
um zu erfahren, wie die Programmierung korrekt erfolgt.
Warum ist das so? Die DataRow-Klasse stellt die tats2chlich in einer Ta-
belle enthaltenen Daten dar. Das heißt, Sie m)ssen auch eine leere Reihe
aus einer vorhandenen Tabelle ableiten, wenn Sie dieser Daten zuweisen
wollen. Dazu dient die Methode NewRow.
Nun werden den Spalten der neuen Reihe die Werte spaltenweise
zugewiesen:
tempRow("name") = "JJrg Krause"
Am Ende wird die neue Spalte der Kollektion der Reihen der
Tabelle angeh$ngt. Da die Reihe vorher aus der Tabelle selbst er-
zeugt wurde, stimmen die Spalten 'berein und der Vorgang ge-
lingt immer:
ds.Tables("Adressen").Rows.Add(tempRow)
Damit ist das Programm auch schon lauff$hig. Nicht gezeigt wur-
den hier die ben#tigten Zuweisungen der Namensr$ume und die
Deklarationen globaler Felder. Konsultieren Sie also unbedingt
den Code auf der CD zum Buch. Das fertige Programm f'hrt zu
einer Anzeige, wie sie in Abbildung 9.20 bereits gezeigt wurde.
Sandini Bib
884 9 Datenbanken und ADO.NET
Tabelle 9.2: Wichtige Eigenschaften der Klasse DataColumn zum Festlegen von
Spalteneigenschaften
Sandini Bib
Datenverwaltung mit ADO.NET 885
Tabelle 9.2: Wichtige Eigenschaften der Klasse DataColumn zum Festlegen von
Spalteneigenschaften (Forts.)
Wenn Sie im DataSet-Objekt Daten speichern, die explizit als XML XML
ausgegeben werden sollen oder die aus einer XML-Quelle stam-
men, k#nnen die Spalten zu einem speziellen Namensraum geh#-
ren. Dann ruft die Eigenschaft NameSpace diesen ab oder legt ihn
fest. Mit Prefix wird der Aliasname des Namespace festgelegt
oder ermittelt.
Ein kleines Programm soll zeigen, wie Sie die Definition von be-
rechneten Spalten mit der Eigenschaft Expression verwenden k#n-
nen. Zuerst folgt wieder ein Blick auf den HTML-Quelltext. Reali-
siert wird ein Euro-W$hrungsumrechner mit einer Besonderheit.
Nach der Auswahl der Ausgangsw$hrung in Euro kann der Be-
nutzer eine Liste von Werten eingeben und sich so die $lteren
Umrechnungen anschauen:
RepeatDirection="Horizontal" />
Tragen Sie einen Wert ein, der der Liste hinzugefZgt werden soll:
<br>
<asp:TextBox Runat="server" ID="Eingabe" />
<asp:Button Runat="server" ID="Absenden" É
OnClick="Absenden_OnClick" Text="Berechnen" />
<asp:Label Runat="server" ID="Fehler" />
</form>
<asp:DataGrid Runat="server" ID="Ausgabe" />
Listing 9.26: Ein komfortabler WDhrungsrechner (DataSetLocalExpression.aspx)
Bevor Sie sich den Code n$her anschauen, soll ein Blick auf das er-
wartete Ergebnis gew$hrt werden:
Wie es Das Erzeugen einer anderen Kultur ist sehr einfach. Vorausset-
funktioniert zung ist die Einbindung des passenden Namensraumes:
Imports System.Globalization
Sandini Bib
Datenverwaltung mit ADO.NET 889
Dann wird eine neue Tabelle erzeugt – Currency –, die sp$ter die
Werte aufnimmt, die der Benutzer eingibt:
Dim waehrungsTabelle As DataTable = New DataTable("Currency")
tempC.Unique = True
waehrungsTabelle.Columns.Add(tempC)
Session("MyDataSet") = ds
ds = CType(Session("MyDataSet"), DataSet)
eine Spalte bedient und die zweite berechnet wird. Das Array be-
steht nur aus einem Element, dem Wert des TextBox-Steuerelements:
Dieses Array wird dann als Parameter zum Erzeugen der neuen
Reihe verwendet. Das passiert innerhalb eines Try-Zweiges, denn
hier kann ein Fehler auftreten. Bei der Definition der Spalte wurde
festgelegt, dass die Werte eindeutig sein m'ssen (UNIQUE). Wenn
nun das Formular mit demselben Wert erneut abgesendet wird,
tritt eine entsprechende Ausnahme bei der Ausf'hrung der fol-
genden Zeile auf:
ds.Tables("Currency").Rows.Add(original)
Catch ex As ConstraintException
Zuletzt folgt noch die Ausgabe der Daten des DataSet an das
DataGrid-Steuerelement.
Zusammenfassung
Das vollst$ndige Programm finden Sie unter dem Namen DataSet-
LocalExpression.aspx.vb. Es zeigt, wie Sie ein DataSet-Objekt ohne
Datenbank erzeugen, mit Tabellen f'llen und praktisch verwen-
den k#nnen. Gegen'ber konventioneller Programmierung ist die
Komplexit$t der Speicherung, Berechnung und Darstellung in ein
leistungsf$higes Objekt integriert worden, was den Code schlan-
ker und schneller macht. Auch bei steigenden Anspr'chen an das
Produkt wird die Programmierung mit DataSet der beste Weg
bleiben, denn es gibt weit mehr Funktionen und Einsatzf$lle, als
hier beschrieben werden konnten. Lassen Sie sich durch die bei-
den Beispiele mit datenbanklosen DataSet-Anwendungen inspirie-
ren, eigene Ideen mit dieser Technik umzusetzen.
In den Beispielen wird durchgehend der SQL Server 2000 als Datenquel-
t le verwendet, sodass Sie nur den Einsatz von SqlDataAdapter sehen. Es
d)rfte sehr einfach sein, das Prinzip auf OleDb zu )bertragen. Leser, die
nur MS Access verwenden k=nnen, sollten sich unbedingt dazu ermutigt
f)hlen, die Programme entsprechend zu ver2ndern.
Daten aus der Der erste Schritt bei der Nutzung des Datenadapters besteht in
Datenbank holen der Abfrage von Daten aus einer existierenden Datenbank. Das
folgende Beispiel zeigt, wie dies erfolgt und wie die ?bergabe der
Daten an ein DataSet und nachfolgend an ein DataGrid (hier mit
dem Namen Artikel) erfolgt. Ausf'hrliche Informationen zu den
Sandini Bib
Datenverwaltung mit ADO.NET 893
da.Fill(ds, "Artikel")
Wenn Sie die Gestaltung sehr schnell vornehmen m=chten, k=nnen Sie
t den Designer in Visual Studio .NET verwenden. Wechseln Sie dazu in
die Entwurfsansicht und w2hlen Sie im Kontextmen) des DataGrid-
Steuerelementes die Option Automatische Formatierung. Im fol-
genden Dialog w2hlen Sie eine Gestaltungsvorlage aus und klicken dann
auf OK.
Fill Freilich steckt weit mehr im Datenadapter als dieses Beispiel zei-
gen konnte. Einiges bietet allein die Methode Fill. Hier folgt eine
alternative ?berladung:
DataTable Abgesehen davon kann Fill auch direkt Daten an ein DataTable-
Objekt 'bergeben, dass dann wiederum in der bereits gezeigten
Art und Weise an ein DataSet weitergereicht wird.
Sandini Bib
Datenverwaltung mit ADO.NET 895
Mit FillSchema k#nnen Sie außerdem veranlassen, dass nur die FillSchema
Struktur der abgefragten Tabelle 'bertragen wird. Dies ist dann
interessant, wenn die Datenbank noch leer ist und erst durch Be-
nutzeraktionen gef'llt werden soll.
An dieser Stelle m'ssen Sie sich zwangsl$ufig ein wenig mit Sche-
mata auseinander setzen. Einige Informationen finden Sie im Ab-
schnitt »Eine sehr kurze Einf'hrung in XSD« ab Seite 450. Denn
das interne Speicherformat im DataSet ist XML. Die Strukturinfor-
mationen der Tabellen werden passend dazu in XSD (XML Sche-
ma Definition Language) gespeichert.
Wenn die Daten einer Abfrage nicht zum vorhandenen Schema Umgang mit
passen, muss es eine Strategie geben, damit umzugehen. Allein das vorhandenen
Schematas
ausl#sen einer Ausnahme ist keine L#sung, denn Teilabfragen sind
typisch, sodass h$ufiger dieser Vorgang auftritt. Die Klasse SqlDa
taAdapter bzw. OleDbDataAdapter bringt dazu eine Eigenschaft mit:
MissingSchemaAction. Damit steuern Sie, wie mit fehlenden oder
'berz$hligen Spalten und bestimmten Spalteneigenschaften verfah-
ren wird, wenn das F'llen eines DataSet erfolgt. Der Eigenschaft
kann eine der folgenden Aufz$hlungen zugewiesen werden.
Sandini Bib
896 9 Datenbanken und ADO.NET
Option Beschreibung
Add F.gt zus'tzliche Spalten hinzu, unabh'ngig davon, ob sie im
Schema schon existieren. Dies ist die Standardeinstellung.
AddWithKey F.gt zus'tzliche Spalten hinzu und erkennt Prim'rschl.ssel.
Error L,st eine Ausnahme aus, wenn eine Spalte im Schema nicht
existiert.
Ignore Spalten, die nicht im Schema existieren, werden ignoriert.
Tabelle 9.3: Steuerung des Verhaltens des Datenadapters bei der DatenCbergabe an
ein DataSet
E Sortieren
E Filtern
Dar'ber hinaus k#nnen Sie die Daten in der Sicht auch $ndern, l#-
schen oder erg$nzen. Die dahinter liegende Tabelle wird dann
ebenfalls aktualisiert und dies wird wiederum in der Datenbank
repr$sentiert.
Sandini Bib
Datenverwaltung mit ADO.NET 897
<h1>DataView</h1>
<h2>Daten mit DataAdapter holen und mit É
DataView filtern/sortieren</h2>
<form runat="server">
(<asp:CheckBox Runat="server" ID="SortierRichtung" É
Text="Absteigend"/>)
sortieren nach:
<asp:RadioButtonList Runat="server" ID="SortierTyp" É
RepeatDirection="Horizontal">
<asp:ListItem Selected="True" Value="preis">É
Preis</asp:ListItem>
<asp:ListItem Value="name">Name</asp:ListItem>
<asp:ListItem Value="filter">Filter:</asp:ListItem>
</asp:RadioButtonList>
<asp:TextBox Runat="server" ID="Filter" Width="100px"/>
(Filter-Option wShlen)
<asp:Button Runat="server" ID="Absenden" Text="Auswahl" É
OnClick="Optionen_Changed"/>
</form>
<asp:DataGrid Runat="server" ID="Artikel" É
BorderColor="#CC9966" É
BorderStyle="None" BorderWidth="1px" É
BackColor="White" CellPadding="4">
<SelectedItemStyle Font-Bold="True" É
ForeColor="#663399" É
BackColor="#FFCC66">
</SelectedItemStyle>
<ItemStyle ForeColor="#330099" BackColor="White">É
</ItemStyle>
<HeaderStyle Font-Bold="True" ForeColor="#FFFFCC" É
BackColor="#990000"></HeaderStyle>
<FooterStyle ForeColor="#330099" BackColor="#FFFFCC">
</FooterStyle>
<PagerStyle HorizontalAlign="Center" É
ForeColor="#330099" É
BackColor="#FFFFCC">
</PagerStyle>
</asp:DataGrid>
Listing 9.31: Sortieren und Filtern mit DataView (DataViewFilterSort.aspx)
Sandini Bib
898 9 Datenbanken und ADO.NET
Erstellt wird eine Liste von Optionsfeldern, die die Auswahl der
Spalte zulassen und als dritte Option das Filtern der Namen nach
einem Bestandteil. Das TextBox-Steuerelement enth$lt den Filter-
wert. Mit dem Klick auf die Schaltfl$che wird eine Methode
Optionen_Changed aufgerufen, die noch erstellt werden muss.
Zuvor ist ein Blick auf die Erstellung des DataSet angebracht. Das
passiert in der Methode Page_Load:
Session("ArtikelDs") = ds
End If
End Sub
Listing 9.32: Erzeugen des DataSet und Speicherung in einer Sitzungsvariablen
(Ausschnitt aus DataViewFilterSort.aspx.vb)
RowFilter Wenn die Option filter gew$hlt wurde, wird aus dem Inhalt des
TextBox-Steuerelements eine Filteranweisung formuliert. Die M#g-
lichkeiten, die hier bestehen, entsprechen denen der Datenbank,
so wie es dort nach der WHERE-Klausel geschrieben wird. Sie k#n-
nen also beispielsweise einen Filter mit der SQL-Option LIKE ent-
werfen:
Sort Alternativ zum Filtern kann auch sortiert werden. Die Spalten-
namen wurden bereits als Werte der Optionsfelder verwendet, so-
dass die Filteranweisungen direkt erzeugt werden. Je nach Zu-
stand des Kontrollk$stchens wird außerdem ASC oder DESC
angeh$ngt. Auch entsprechen die M#glichkeiten denen von SQL
nach der ORDER BY-Bedingung.
Die Abfragesprache, die mit Sort und RowFilter verwendet wird, ent-
spricht zwar SQL, wird aber nicht direkt an die Datenbank weiterge-
geben. Der Sprachumfang ist etwas geringer als von T-SQL vorgegeben.
Tats2chlich wird auch nicht die Datenbank abgefragt, sondern es werden
nur die lokalen Daten in der Datenansicht gefiltert.
E Operatoren
E Aggregat-Funktionen
E Allgemeine Funktionen
E Filterstatus-Eigenschaften
Operator Beschreibung
AND Logische Verkn.pfungen zwischen Teilausdr.cken
OR (Und, Oder, Nicht)
NOT
Sandini Bib
Datenverwaltung mit ADO.NET 901
Operator Beschreibung
> Bedingungsoperatoren zur Bildung von Ausdr.cken
<
<=
>=
<>
=
+ Mathematische Operatoren zum Berechnen in Ausdr.cken
-
*
/
%
IN Spezifizierung einer Liste: IN (Wert1, Wert2, Wert3)
LIKE Suchen von Teilen eines Ausdrucks mit Hilfe von Platzhalter-
zeichen (»%« f.r beliebige und »_« f.r ein beliebiges Zeichen)
dv.RowStateFilter = RowStateFilter.CurrentRows
Wert Bedeutung
Added Nur in dieser Ansicht hinzugef.gte Reihen
CurrentRows Aktuelle Reihen, also originale, hinzugef.gt und
ge'nderte, nicht jedoch gel,schte
Deleted Gel,schte Reihen
ModifiedCurrent Aktuelle Version einer ver'nderten Reihe
ModifiedOriginal Originale (urspr.ngliche) Version einer ver'nderten
Reihe
None Keine Optionen (Standardeinstellung)
Wert Bedeutung
OriginalRows Die urspr.ngliche Reihe ohne Beachtung ver'nder-
ter oder gel,schter Reihen
Unchanged Alle unver'nderten Reihen
Die Optionen sind Bitfelder und k#nnen deshalb mit dem Or-Ope-
rator verkn'pft werden, wenn dies sinnvoll ist.
Bevor Sie die ersten Schritte mit einer Aktualisierung gehen, sollten Sie
sich die M=glichkeiten der vorlagenorientierten Programmierung mit
DataGrid ansehen, die vieles vereinfacht. Genauer wird im Abschnitt 6.6,
t
»Vorlagengebundene Daten-Steuerelemente« ab Seite 566 darauf einge-
gangen. Andererseits erf)llt das DataGrid nie alle Anspr)che, es ist des-
halb gut zu wissen, wie Aktualisierungen direkter programmiert werden.
Die Vorlage
Die eigentliche Arbeit wird in der Code-Datei erledigt, entspre-
chend beschr$nkt sich der HTML-Teil auf wenige Steuerelemente.
Außerdem soll diesmal keines der fertigen Daten-Steuerelemente
verwendet werden.
Die Motivation fr dieses Programm lag in zwei Aspekten: Zum Motivation
einen sollte gezeigt werden, dass auch beim Verzicht auf DataGrid
eine ansprechende L"sung mit wenigen Zeilen Code m"glich ist.
Zum anderen sollte eine Funktion realisiert werden, die DataGrid
nicht bietet. Die Auswahl der Zeilen ist nmlich ber das Java-
Sandini Bib
906 9 Datenbanken und ADO.NET
Die Code-Datei
DataViewEdi- Die Code-Datei beginnt mit den zustzlich n"tigen Imports-
tor.aspx.vb Anweisungen. Anhand der Zeile Imports System.Data.SqlClient ist
erkennbar, dass der SQL Server als Datenquelle dienen soll. Nun
beginnt die Definition der Klasse DataViewEditor, abgeleitet von
Page und mit einigen "ffentlichen Feldern. Die Abfrage der Arti-
keltabelle wird fest vorgegeben, alle anderen SQL-Befehle werden
spter von ADO.NET automatisch erzeugt.
Private tr As TableRow
Private tc As TableCell
Private ds As DataSet
Private dv As DataView
Protected WithEvents ArtikelHinzu As Button
Private da As SqlDataAdapter
ArtikelTabelle.Controls.Clear()
ArtikelTabelle.GridLines = GridLines.Both
ArtikelTabelle.Rows.Add(AddHeader())
For i = 0 To dv.Table.Rows.Count - 1
Restart:
r = dv.Table.Rows(i)
tr = New TableRow()
If r.RowState = DataRowState.Deleted Then
i = i + 1
GoTo Restart
End If
If i = EditRow Or r.RowState = DataRowState.Added Then
Jede Reihe besteht aus Zellen. Diese werden auf Basis der
DataColumns-Kollektion erstellt, die aus der Eigenschaft Columns ent-
nommen wird. Eine Besonderheit stellt die Spalte id dar, in der
statt des Eingabefeldes zum %ndern die Schaltflchen eingeblen-
det werden:
b = New Button()
b.Text = "OK"
b.BackColor = Color.Green
AddHandler b.Command, AddressOf Artikel_Edit
b.CommandName = IIf(r.RowState = DataRowState.Added, "Edit",
"Add")
b.CommandArgument = i.ToString()
tc.Controls.Add(b)
b = New Button()
b.Text = "Del"
b.BackColor = Color.Red
AddHandler b.Command, AddressOf Artikel_Delete
b.CommandName = "FeldNummer"
b.CommandArgument = i.ToString()
tc.Controls.Add(b)
End If
Nun werden die »normalen« Zellen erzeugt, also alle anderen, die Auf Maus
sich nicht im Bearbeitungsmodus befinden. Damit die Reaktion reagieren
auf onMouseOver erfolgt, ist JavaScript erforderlich. Dies wird der
Tabellenreihe tr als Attribut-Parameter bergeben. Die einzige
Aufgabe besteht darin, das Formular sich selbst aufrufen zu las-
sen und die Nummer der Reihe zu bergeben. Die ?bergabe der
Nummer erfolgt mit einem versteckten Feld, das in der HTML-
Seite fest definiert wurde. Es steht als HTML Server-Steuerele-
ment FeldNummer zur Verfgung. Das Senden des Formulars be-
schrnkt sich auf den Aufruf der submit()-Methode in JavaScript;
das korrekte Ziel hat ASP.NET eingetragen, weil das Formular
mit runat="server" gekennzeichnet ist. Die brigen Attribute die-
nen ebenfalls der Maussteuerung:
tr.Cells.Add(tc)
Next
Else
tr.Attributes("onClick") É
=
String.Format("document.DataViewEditor.FeldNummer.value='{0}'; É
document.DataViewEditor.submit ();", i.ToString())
tr.Attributes("onMouseOver") É
= "this.style.cursor='hand'; É
this.style.backgroundColor='red';"
tr.Attributes("onMouseOut") É
= "this.style.backgroundColor='white'"
Nach der Programmierung der interaktiven Steuerung der Reihe Die Reihen
werden die Tabellenzellen erzeugt. Hier wird einfach der Inhalt hinzuf gen
Sandini Bib
910 9 Datenbanken und ADO.NET
der Datentabelle den Zellen als Text zugewiesen. Die fertige Reihe
wird dann an die Tabelle angefgt:
Dim c As DataColumn
For Each c In r.Table.Columns
tc = New TableCell()
tc.Text = r(c).ToString()
tr.Cells.Add(tc)
Next
End If
ArtikelTabelle.Rows.Add(tr)
Next
End Sub
Page_Load Nach den Hilfsmethoden zum Aufbau der Anzeige beginnt das
eigentliche Programm, wie blich in Page_Load. Beim Start der Ap-
plikation wird versucht, den Datenadapter aus einer Applika-
tionsvariablen auszulesen. Falls er nicht existiert (da Is Nothing),
wird ein neuer erzeugt und zugewiesen. Der Trick daran: Es exis-
tiert nur ein Datenadapter fr alle Benutzer und der erste Benut-
zer, der die Applikation startet, erzeugt ihn. Die Steuerung der
Anzeige erfolgt dann individuell in jeder einzelnen Sitzung mit
Sitzungsvariablen und der Datenansicht. Diese Strategie reduziert
die Datenbankzugriffe auf das unbedingt notwendige Minimum.
Ganz unkritisch ist sie dennoch nicht, aber auf m"gliche Probleme
und deren L"sung wird spter eingegangen.
Datenadapter Vorerst ist ein Blick auf den Datenadapter hilfreich. Nach dem
Anlegen des Adapters, basierend auf der Standardabfrage SELECT
* FROM Artikel wird der Parameter AddWithKey gesetzt. Die auto-
matische Verwaltung der %nderungen in der Datenansicht funk-
tioniert nur, wenn ein Primrschlssel existiert. Dieser Parameter
bernimmt den Schlssel aus der Datenbank. Dann wird ein
SqlCommandBuilder-Objekt erzeugt. Der Konstruktor fgt dem Da-
tenadapter da automatisch generierte SQL-Befehle hinzu. Damit
reicht spter der Zugriff auf die abgeleitete Datenansicht.
Das DataSet, das die Daten der Abfrage aufnimmt, ist natrlich DataSet
fr jede Sitzung individuell – die Synchronisierung passiert erst
spter. Es wird beim ersten Abruf der Seite erzeugt, wenn die Ei-
genschaft IsPostBack gleich False ist. Gleichzeitig wird auch die
Datenansicht erstellt – hier einmal ganz einfach ohne Sortierung
oder Filterung. Sie k"nnen dies aber leicht ergnzen. Mit diesen
Daten wird dann GenerateTable aufgerufen.
End If
If Not Page.IsPostBack Then
ds = New DataSet()
da.Fill(ds, "Artikel")
Session("ArtikelDs") = ds
dv = New DataView(ds.Tables("Artikel"))
GenerateTable(dv, -1)
Else
In allen anderen Fllen wird versucht, das DataSet aus der Sit-
zungsvariablen ArtikelDs zu entnehmen. Es ist außerdem beim
Zurcksenden des Formulars festzustellen, welcher Wert im ver-
steckten Feld FeldNummer steht. Dies zeigt die zu bearbeitende
Zeile an. Falls die Auswahl erfolgte, obwohl noch kein DataSet
existiert, wird dieses erzeugt. Das passiert, wenn jemand das For-
mular einer frheren Sitzung speichert.
ds = CType(Session("ArtikelDs"), DataSet)
If Not ds Is Nothing Then
dv = New DataView(ds.Tables("Artikel"))
GenerateTable(dv, Int32.Parse(FeldNummer.Value))
Else
ds = New DataSet()
da.Fill(ds, "Artikel")
Session("ArtikelDs") = ds
dv = New DataView(ds.Tables("Artikel"))
GenerateTable(dv, -1)
End If
End If
End Sub
sentiert: Tritt der Fehler auf, wird dem Benutzer ein Link ange-
zeigt, der die Tabelle mit der Datenbank synchronisiert. Die fol-
gende Funktion erzeugt das entsprechende Steuerelement:
Die Methode Artikel_Edit dient der Bearbeitung der Daten einer Artikel_Edit
Reihe. Auch hier wird lediglich das DataView-Objekt gendert. Mit
dem Aufruf von Update wird dann der passende SQL-Befehl dem
DataAdapter entnommen (das dort von CommandBuilder erzeugt wur-
de) und an die Datenbank gesendet. Auch hier kann die beschrie-
bene Situation auftreten, dass ein Datensatz gendert wird, der
sich gerade bei einem anderen Benutzer in Bearbeitung befand.
Mangels Datensatzverriegelung – die Daten sind im DataSet losge-
l"st – ist auch hier eine Ausnahme vom Typ DBConcurrencyException
zu erwarten.
Sandini Bib
914 9 Datenbanken und ADO.NET
Dann wird der Text definiert, der die Basis des SQL-Befehls dar-
stellt:
sc.CommandText = "BestellterArtikel"
Anzugeben ist noch der Typ, hier also eine gespeicherte Prozedur:
sc.CommandType = CommandType.StoredProcedure
Etwas aufwndiger ist die Definition der Parameter. Dazu wird je-
weils ein Objekt vom Typ SqlParameter ben"tigt. Wie das genau
funktioniert, zeigt das kleines Programm in Listing 9.35.
Sandini Bib
916 9 Datenbanken und ADO.NET
Wenn Sie statt dem SQL Server einen Datenbankzugriff 'ber OleDb
t vornehmen, werden die ad*quaten Klassen mit dem Pr*fix »OleDb« statt
»Sql« verwendet. Einziger Unterschied: Bei den Parametern im Kom-
mando erfolgt die Angabe nicht mit @name, sondern durch das Parame-
tersymbol »?«. Die Zuweisung erfolgt fortlaufend in der Reihenfolge der
Definition.
<body>
<h1>DataAdapter, Command</h1>
<h2>Nutzung gespeicherter Prozeduren</h2>
WMhlen Sie eine Artikelnummer, um die Bestellungen dazu zu sehen:
<form id="DataAdapterCommand" method="post" runat="server">
<asp:DropDownList Runat="server" ID="ArtikelNummer" É
AutoPostBack="True"/>
</form>
<asp:DataGrid Runat="server" ID="Bestellungen"/>
</body>
Listing 9.35: Vorlage fr das Abfrageprogramm (DataAdapterCommand.aspx)
Das fhrt dann je nach Artikel und Inhalt der Bestelltabelle zu et-
wa folgender Ausgabe:
Sandini Bib
Datenverwaltung mit ADO.NET 917
sp.DbType = DbType.Int32
sp.Direction = ParameterDirection.Input
sc.Parameters.Add(sp)
da.SelectCommand = sc
Session("Adapter") = da
Else
da = CType(Session("Adapter"), SqlDataAdapter)
If Not da Is Nothing Then
ds = New DataSet()
da.SelectCommand.Parameters("@ArtikelNummer").Value É
= ArtikelNummer.SelectedItem.Value
da.Fill(ds)
Bestellungen.DataSource = ds
Bestellungen.DataBind()
End If
End If
End Sub
End Class
Listing 9.36: Die Code-Datei (DataAdapterCommand.aspx.vb)
Wie es Der erste Teil nutzt einen schnellen DataReader, um die Auswahl-
funktioniert liste zu fllen. Das hier bereits verwendete Command-Objekt wird
nun zur Nutzung der gespeicherten Prozedur eingesetzt. Als
Kommandotext wird der Name der Prozedur genannt:
sc.CommandText = "BestellterArtikel"
sc.CommandType = CommandType.StoredProcedure
sp = new SqlParameter()
sp.ParameterName = "@ArtikelNummer"
Datentyp Nun ist der Datentyp in der Prozedur entsprechend dem SQL-
Datentyp festzulegen:
sp.DbType = DbType.Int32
Richtung Zuletzt ist noch die Richtung anzugeben, es handelt sich offen-
sichtlich um einen Eingabeparameter:
sp.Direction = ParameterDirection.Input
Sandini Bib
Datenverwaltung mit ADO.NET 919
sc.Parameters.Add(sp)
da.SelectCommand = sc
Session("Adapter") = da
Beim Aufruf der Seite ber das Formular wird der zweite Teil der Page_Load
Page_Load-Methode verarbeitet. Hier wird zuerst der Datenadapter
aus der Sitzungsvariablen restauriert:
da = CType(Session("Adapter"), SqlDataAdapter)
Jetzt wird fr die Anzeige der Daten ein neues DataSet-Objekt er-
stellt:
ds = New DataSet()
Bisher fehlte noch der eigentliche Wert, der dem Parameter ber-
geben wird. Ohne diesen Wert kann die eigentliche Abfrage nicht
ausgefhrt werden. Sie k"nnen den Parameterwert direkt anspre-
chen, indem auf die SelectCommand-Eigenschaft zugegriffen wird.
Die Nummer wird der Auswahlliste entnommen. Parameter ak-
zeptieren als Datentyp Object, sodass Sie hier den Wert als Zei-
chenkette bernehmen k"nnen. Es wird dann intern versucht, die-
sen Wert in den ben"tigten Datentyp zu bernehmen. In der
Praxis ist es sicher sinnvoll, hier eine Typprfung auf anderem
Wege vorzunehmen oder eine Ausnahmebehandlung mit Try-
Catch zu implementieren.
da.SelectCommand.Parameters("@ArtikelNummer").Value É
= ArtikelNummer.SelectedItem.Value
Sandini Bib
920 9 Datenbanken und ADO.NET
da.Fill(ds)
Bestellungen.DataSource = ds
E RowUpdating
Dieses Ereignis wird ausgel"st, wenn der Aktualisierungspro-
zess beginnt.
E RowUpdated
Mit Hilfe dieses Ereignisses k"nnen Sie eigene Prozesse an das
Ende des Aktualisierungsprozesses anhngen.
Eigenschaft Beschreibung
Command Command-Objekt fr die Aktualisierung
Errors Fehler, die erzeugt wurden
Row Die Reihe, die aktualisiert wird
StatementType Typ des Kommandos
Status Status; eine Aufz(hlung des Typs UpdateStatus
TableMapping DataTableMapping-Objekt das verwendet wurde
Zeitgleich mit dem Aufruf des Explorers erscheint eine neue Sym-
bolleiste, die das Ausfhren von SQL und die Generierung von
Abfragen erlaubt. Wenn Sie diese Leiste nicht sehen, whlen Sie
im Kontextmen der Symbolleisten den Eintrag Datenbankent-
wurf.
Die Tabelle wird jetzt angezeigt. Wenn Sie Daten im Gitter n-
dern, wird dies sofort an die Datenbank bertragen. Neue Reihen
fgen Sie hinzu, indem Sie diese in die Reihe mit dem Stern am
Anfang schreiben.
Klicken Sie nun in den Bereich SQL mit der rechten Maustaste. Im INSERT INTO
Kontextmen whlen Sie Typ %ndern und dort Werte einfgen.
Die %nderung des Typs ist auch ber die Symbolleiste m"glich.
Aktivieren Sie in der Tabellenansicht die Spalten, die hinzugefgt
werden sollen. Tragen Sie im Bereich Datenblatt die einzuf-
genden Werte ein.
Zum L"schen von Daten whlen Sie im Kontextmen Typ %ndern DELETE FROM
und dort L'schen. Whlen Sie im Bereich Datenblatt die Spalte
aus, die als L"schkriterium herangezogen werden soll. In der
Spalte Kriterien k"nnen Sie nun die WHERE-Bedingungen angeben.
Innerhalb der Reihen werden mehrere Bedingungen OR-verknpft,
zwischen den Reihen mit AND.
UPDATE Zum Erzeugen eines UPDATE-Befehls whlen Sie die Option Aktua-
lisieren. Auch hier kann hnlich wie bei DELETE eine Reihe von
Kriterien definiert werden, die in der WHERE-Bedingung genutzt
werden.
Die noch nicht beschriebene Option Ergebnisse einfgen erzeugt
eine Kombination aus SELECT und INSERT, wobei die Ergebnisse der
SELECT-Abfrage in eine andere Tabelle mittels INSERT eingefgt
werden.
E Current
Diese Eigenschaft gibt das aktuelle Element aus der Auflistung
zurck.
E MoveNext
Mit dieser Methode wird der Wechsel zum nchsten Element
veranlasst. Wenn kein weiteres Element mehr verfgbar ist,
wird False zurckgegeben.
Sandini Bib
Die Datenbindung an Steuerelemente 929
E Reset
Diese Methode setzt den Zeiger auf die Elemente wieder an
den Anfang zurck.
E IsFixedSize
Zeigt an, dass die Gr"ße unvernderlich ist.
E IsReadOnly
Zeit an, dass der Inhalt schreibgeschtzt ist.
E Item
Gibt ein Element zurck. In VB.NET ist dies auch die Stan-
dardmethode, weshalb der Zugriff auch ohne den Methoden-
namen mit der Arrayschreibweise erfolgen kann.
Das Attribut <Serializable ()> ist notwendig, weil die Instanz der <Serializable ()>
Klasse spter im Anzeigestatus (ViewState) gespeichert werden
soll und dazu serialisiert werden muss. Um den Vorgang selbst
mssen Sie sich nicht kmmern.
<Serializable()> _
Public Class NameListEnumerator
Implements IEnumerator
IEnumerable Nun wird die eigentliche Liste implementiert, die die Schnittstelle
implementieren IEnumerable nutzt. Hier werden die fehlenden Methoden zur Be-
nutzung der Liste programmiert. Add fgt Werte hinzu, Clear
l"scht alle Werte.
<Serializable()> _
Public Class NameList
Implements IEnumerable
Dim _nlg As NameListEnumerator
Ereignisbehand- Jetzt folgt die Erstellung der eigentlichen Hauptklasse. Hier wer-
lungsmethode den die Ereignisbehandlungsmethoden fr die beiden Schaltfl-
chen zum Hinzufgen und L"schen geschrieben. Die fertige Liste
wird außerdem im ViewState-Objekt gespeichert.
Public nl As NameList
Am Ende folgt die Bindung der Datenquelle in der blichen Form. Die Bindung an
Die Art der Implementierung war so gewhlt, dass das Steuerele- die Datenquelle
ment mit den Informationen umgehen kann.
nl = CType(ViewState("nl"), NameList)
NamensListe.DataSource = nl
AddHandler NamensListe.DataBinding, AddressOf OnBinding
End If
End Sub
End Class
Sandini Bib
934 9 Datenbanken und ADO.NET
Mit dem Wenn Sie den Debugger starten und das Programm schrittweise
Debugger durchgehen, k"nnen Sie feststellen, wie nach dem Aufruf der Me-
untersuchen
thode DataBind als Nchstes die Methode MoveNext in NameListEnu-
merator aufgerufen wird, danach Current usw. – fr jedes enthalte-
ne Element. Die Datenbindung »bedient« sich quasi an Ihren
Methoden. Auf diesem Wege k"nnen Sie leicht komplexe Abfra-
gen realisieren und trotzdem die vorgefertigten Steuerelemente
zur Darstellung nutzen.
Als Letztes soll ein Blick auf den HTML-Text zeigen, wie die Da-
tenquelle genutzt wird:
<body>
<h1>Eigene Datenquelle implementieren</h1>
<h2>IEnumerator</h2>
<form id="DataSourceImplement" method="post" É
runat="server">
<asp:TextBox Runat="server" ID="Name"/>
<asp:Button Runat="server" ID="Send" Text="Eintragen"É
OnClick="Eintragen_Click"/>
<asp:Button Runat="server" ID="Clear" Text="LPschen"É
OnClick="Loeschen_Click"/>
</form>
<asp:DataList Runat="server" ID="NamensListe">
<ItemTemplate>
<%# Container.DataItem %>
</ItemTemplate>
</asp:DataList>
</body>
Listing 9.37: Die Nutzung der selbst erstellten Datenquelle (DataSourceImplement.aspx)
Das funktioniert, weil die Datenquelle nur einen einzigen Wert Bindung von
pro Abruf zurckgibt – die Eigenschaft Current hat das erledigt. Listen
Wenn nun eine Klasse verwendet wird, die mehrere Werte pro
Datensatz enthlt, muss eine Auswahl getroffen werden. Ver-
zeichnisse wie Hashtable implementieren Schlssel/Werte-Paare.
Die Eigenschaften, die den Zugriff erlauben, heißen Key und Value.
Zur Bindung der Werte schreiben Sie dann:
Container.DataItem.Key
Container.DataItem.Value
Generell handelt es sich um eine so genannte spte Bindung. Das Sp6te Bindung
heißt, der Vorgang der Datenbindung wird vollstndig abge-
schlossen, die Seite wird aufgebaut und dann erst – unmittelbar
vor der Auslieferung – werden die Eval bergebenen Datenwerte
analysiert und bearbeitet. ASP.NET nutzt intern die Reflektion ge-
nannte Technik, mit der zur Laufzeit Informationen ber Klassen
und Methoden ermittelt werden. Das ist zwar sehr leistungsfhig,
greift aber praktisch in eine bereits vorkompilierte Seite ein. Der
Nachteil dabei: Die Methode Eval ist langsamer. Eingesetzt wird
sie vor allem, um Daten vielfltig fr die Ausgabe zu formatieren.
Sandini Bib
936 9 Datenbanken und ADO.NET
Auf die Formatierung und die weiteren Teile der Syntax wurde
bereits in Abschnitt »Eine Einfhrung in die Datenbindung in
Vorlagen« ab Seite 571 eingegangen.
9.5.3 Ereignisbehandlung
Sie k"nnen den Zeitpunkt der Bindung der Daten nutzen, um da-
von abhngende Aktionen zu starten. Dazu enthalten alle daten-
gebundenen Steuerelemente ein Ereignis DataBinding. Der folgen-
de Code, der ergnzend im letzten Beispiel platziert wurde, zeigt
die Vorgehensweise.
Wie es Hier wird dem Label-Steuerelement Counter die Anzahl der Da-
funktioniert tenstze zugewiesen, die derzeit in dem Daten-Steuerelement
sind, das das Datenbindungsereignis ausl"ste. Im vorhergehen-
den Beispiel fehlte eine explizite Methode »Count« zur Ermittlung
der Anzahl der Elemente. Die hier gezeigte Vorgehensweise kom-
pensiert diesen Mangel. Man muss aber eingestehen, dass es nicht
zwingend erforderlich ist, dazu Ereignisse zu verwenden. Die
Verwendung von Ereignissen ist oft kompakter und eleganter,
aber nur selten besser lesbar.
Sandini Bib
Indexdienst programmieren 937
Der Indexdienst
Der Indexdienst geh"rt fr viele Webentwickler offensichtlich zu SQL nutzen
den großen Unbekannten, denn nur selten kommt er auf Servern
zusammen mit programmierten Abfragen zum Einsatz. Das mag
auch daran liegen, dass Microsoft vor langer Zeit eine eigene Ab-
fragesprache propagiert hat, die man zu Recht als kryptisch be-
zeichnen kann. Die in allen Windows-Versionen mit NT-Kern be-
findliche Version kann jedoch auch ber SQL-Anweisungen
abgefragt werden. Es sind zustzlich proprietre Erweiterungen
hinzugefgt worden, die auf die Bedrfnisse der Katalogabfrage
zugeschnitten sind. Außerdem beschrnken sich die M"glichkei-
ten auf den Einsatz von SELECT. Die erste wichtige Kenntnis ist also
die des SQL-Dialekts des Indexdienstes.
Die zweite wichtige Kenntnis ist der Name des OleDb-Providers OleDb-Provider
fr den Indexdienst: »MSIDXS« (Microsoft Indexing Service). Da
ADO.NET neben dem SQL Server standardmßig Klassen zum
Zugriff auf OleDb-Quellen bietet, kann die Verwendung in einer
ASP.NET-Anwendung kein großes Problem darstellen.
Sandini Bib
938 9 Datenbanken und ADO.NET
Der Katalog Als Nchstes gilt es nun einen Katalog vorzubereiten. Wenn Sie
den Indexdienst noch nicht verwenden, gehen Sie dazu folgender-
maßen vor:
SELECT Columns|Viewname|*
From_Clause
[WHERE_Clause]
[Order_Clause]
[Servername.Catalog] É
SCOPE([SHALLOW | DEEP TRAVERSAL OF É
("Path" [, "Path"]]))
Die Option hinter SCOPE kann entfallen. Wenn sie nicht gesetzt
ist, werden alle Verzeichnisse im Katalog durchsucht, begin-
nend mit dem Stammverzeichnis. Wird die Option SHALLOW ge-
setzt, werden nur die angegebenen Pfade durchsucht; mit DEEP
werden auch untergeordnete einbezogen. Fr WHERE_Clause
k"nnen so genannte Prdikate zusammen mit Booleschen
Operatoren (AND, OR, NOT) eingesetzt werden:
Spalte Bedeutung
Contents Dokumentinhalt
Characterization Zusammenfassung einer Fundstelle. Die Anzahl der
Zeichen kann in den Eigenschaften des Katalogs
bestimmt werden (siehe Dialogfenster des Katalog-
managers)
Filename Dateiname
Size Dateigr@ße in Bytes
Path Pfad und Dateiname
Vpath Virtueller Pfad und Dateiname
HitCount Anzahl der Fundstellen des Suchwortes im
Dokument
Rank Rang (Wert zwischen 0 und 1.000)
Create Zeitpunkt, wann die Datei erzeugt wurde
Write Zeitpunkt, wann die Datei zuletzt beschrieben
wurde
DocTitle Titel des Dokuments (wenn vorhanden)
DocSubject Betreff (trifft beispielsweise fr Word zu)
DocPageCount Anzahl der Seiten (trifft beispielsweise fr Word zu)
DocAuthor Autor (trifft beispielsweise fr Word zu)
DocKeywords Schlsselw@rter (trifft beispielsweise fr Word
und HTML zu)
DocComments Kommentare (trifft beispielsweise fr Word zu)
Sandini Bib
Indexdienst programmieren 941
Fallen immer noch sehr viele Resultate an, muss die Ausgabe ge- Ausgabe-
steuert werden. Zum einen sollte eine seitenweise Ausgabe er- aufbereitung
Wie es Der zweite Teil stellt die Suchergebnisse dar. Damit die vorberei-
funktioniert tete, leere Tabelle nicht st"rt, wird der gesamte Teil in ein Panel-
Steuerelement eingebaut, das anfangs unsichtbar ist:
<asp:Panel Runat="server" ID="searchResults" Visible="false">
Imports System.Data
Imports System.Data.OleDb
Sandini Bib
944 9 Datenbanken und ADO.NET
Ereignisablauf
Das Erstellen von Formularen ist eher lstig. Es ist nichtsdesto-
trotz wichtig, hierbei Sorgfalt walten zu lassen, denn der Benutzer
wird nur mit der von Ihnen entworfenen Oberflche konfrontiert.
Natrlich muss der Code dahinter auch perfekt sein. Ein erster
Ansatz soll hier entwickelt werden. Die Ablage der Klasse erfolgt
als Code Behind-Datei im Namespace Addison.VBNet.Data und
dem Klassennamen SearchForm. Sie erbt – wie alle Klassen zur Sei-
tensteuerung – von Page:
Suchen im Katalog
Der Code setzt voraus, dass im Indexdienst ein Katalog mit dem Den Katalog
Namen »Web« eingerichtet wurde und durchsuchbar ist. Der verwenden
Katalog durchsucht blicherweise den Pfad ab %systemroot%\
inetpub abwrts. Wenn Sie mehrere Domnen hosten, sollten Sie
daran denken, jedem Stammpfad einen eigenen Katalog zu spen-
dieren, sonst durchsuchen sich die Prsenzen gegenseitig. Die
Auswahl des Kataloges erfolgt in der Verbindungszeichenfolge
des OleDb-Providers. Der vom Programm fr die Abfrage erzeug-
te SQL-Code bezieht sich dann auf diesen Katalog.
Im nchsten Schritt mssen die Daten dem DataSet als Tabelle hin-
zugefgt werden. Die Abfrage wird hier willkrlich mit »Index-
Result« bezeichnet. Von Vorteil ist die Art der Datenhaltung. Die
Abfrageergebnisse werden im lokalen Speicher des Webservers
vorgehalten und nachfolgende Zugriffe darauf erfordern keine er-
Sandini Bib
948 9 Datenbanken und ADO.NET
resultTable.DataSource = oDS
resultTable.DataBind()
resultTable.CurrentPageIndex = e.NewPageIndex
resultTable.DataSource = oDS
resultTable.DataBind()
Die kleine Applikation zeigt, wie mit nur wenigen Zeilen Code ei- Fazit
ne komfortable Suchmaschine auf Basis des Indexdienstes ent-
wickelt werden kann. Dabei wird einfach der OleDb-Provider ver-
wendet, der mit Windows installiert wurde. Ein solcher Provider
steht fr viele andere Datenverarbeitungsprogramme ebenfalls
zur Verfgung, sodass der Einsatz zusammen mit ASP.NET sehr
leicht m"glich ist. Vor allem die Daten-Steuerelemente wie
DataGrid lassen die Ausgabe dann mit einfachen Mitteln m"glich
werden.
Sandini Bib
950 9 Datenbanken und ADO.NET
Abbildung 9.35: Erfolgreiche Abfrage des Indexdienstes mit ASP.NET und seitenweiser
Ausgabe der Ergebnisse
Sandini Bib
C Professionelle
Techniken in
ASP.NET
Sandini Bib
Sandini Bib
10 Konfiguration, Optimierung
und Sicherheit
10.1 Schnellstart
Dieser Abschnitt gibt einen kompakten ?berblick ber das Thema
und zeigt sinnvolle Verknpfungen mit ergnzenden und vorberei-
tenden Kapiteln. Der Wegweiser in die Referenz hilft, die passen-
den Seiten in der MSDN-Online-Referenz besonders schnell zu
finden.
10.2.1 Cbersicht
Folgende Direktiven sind verfgbar:
E @Page
Hiermit werden Vorgnge gesteuert, die unmittelbar mit der
Ausfhrung der Seite zu tun haben.
E @Control
Mit dieser Direktive werden Benutzer-Steuerelemente kontrol-
liert. Die Attribute sind mit @Page vergleichbar.
E @Import
Mit dieser Direktive werden Namensrume aus dem .NET-
Framework importiert. Dies ist notwendig, wenn Code Behind
nicht verwendet wird, da in ASP.NET-Vorlagen die Anwei-
sung Imports nicht eingesetzt werden kann, mit der blicher-
weise Namensrume importiert werden.
E @Implements
Diese Direktive importiert eine Schnittstellenbeschreibung (In-
terface) aus dem .NET-Framework.
Sandini Bib
Konfiguration einzelner Seiten: Die Direktiven 955
E @Register
Hiermit werden Benutzer-Steuerelemente (User Controls) an-
gemeldet, sodass der Compiler diese finden und einbinden
kann.
E @Assembly
Die Nachfolger der DLLs in Windows sind in .NET Assem-
blies. Sie enthalten praktisch bereits bersetzten Code in der
Intermediate Language. Mit dieser Direktive k"nnen Sie As-
semblies direkt nutzen.
E @OutputCache
Jede Seite, die auf dem Server erzeugt wird, kann zwischen-
gespeichert werden. Dies erh"ht die Systemleistung und ver-
ringert die Prozessorlast. Fr den korrekten Aufbau der Seite
im Browser ist die Kontrolle dieses Vorgangs wichtig. Die Di-
rektive steuert dies.
E @Reference
Dieses Element stellt fr die Verbindung von Seiten bei der
Steuerungsweitergabe mit Server.Transfer die Referenz her.
Trace Wenn Sie noch mehr Informationen ber den Gesamtzustand des
Systems ben"tigen, um die Ursache eines Laufzeitfehlers zu fin-
den, ergnzen Sie das Attribut trace="True".
Sandini Bib
Konfiguration einzelner Seiten: Die Direktiven 959
E System
E System.Collections
E System.Collections.Specialized
E System.Configuration
E System.IO
E System.Text
E System.Text.RegularExpressions
E System.Web
E System.Web.Caching
E System.Web.Security
E System.Web.SessionState
E System.Web.UI
E System.Web.UI.HtmlControls
E System.Web.UI.WebControls
Festgelegt wird das Prfix, den das Element auf der Seite verwen-
det sowie der Name und der Pfad, wo die ascx-Datei gespeichert
wurde. Eine Anwendung finden Sie unter anderem im Abschnitt
7.2, »Modularer Code mit Benutzer-Steuerelementen« ab Seite 647.
Sandini Bib
960 10 Konfiguration, Optimierung und Sicherheit
VaryByControl Name des Steuerelements, auf das sich der Cache bezieht.
Nur zul(ssig im Steuerelemente-Caching.
mssen Sie sich nicht kmmern. Es wird weder ein Neustart der
Applikation noch des IIS gefordert. Tatschlich ldt ASP.NET die
Datei beim ersten Aufruf und stellt den Inhalt dann aus dem Spei-
cher zur Verfgung. Nur wenn sich %nderungen ergeben, wird
sie neu geladen. Insofern ist die stndige Nutzung nicht mit Fest-
plattenzugriffen verbunden, %nderungen wirken sich aber den-
noch sofort aus.
<configuration>
<system.web>
<authentication>
<forms>
<credentials>
<passport>
<authorization>
<allow>
<deny>
<browserCaps>
<result>
<use>
<filter>
<case>
<clientTarget>
<add>
<remove>
<clear>
<compilation>
<compilers>
<compiler>
<assemblies>
<add>
<remove>
<clear>
<customErrors>
<error>
<globalization>
<httpHandlers>
<add>
<remove>
<clear>
<httpModules>
<add>
<remove>
<clear>
<httpRuntime>
Sandini Bib
964 10 Konfiguration, Optimierung und Sicherheit
<identity>
<machineKey>
<pages>
<processModel>
<securityPolicy>
<trustLevel>
<sessionState>
<trace>
<trust>
<webServices>
<protocols>
<add>
<remove>
<clear>
<serviceDescriptionFormatExtensionTypes>
<add>
<remove>
<clear>
<soapExtensionTypes>
<add>
<soapExtensionReflectorTypes>
<add>
<soapExtensionImporterTypes>
<add>
<WsdlHelpGenerator>
</webServices>
</system.web>
</configuration>
<configuration>
<system.web>
<!-- Hier stehen die Tags -->
</system.web>
</configuration>
<configuration>
<system.web>
<!-- Hier stehen die Tags -->
</system.web>
<location path="data/special">
<system.web>
<!-- Hier stehen die Tags -->
</system.web>
</location>
</configuration>
Sandini Bib
966 10 Konfiguration, Optimierung und Sicherheit
Die Einstellungen lassen sich natrlich auch fr die gesamte Ma-
schine vornehmen. Dies erfolgt dann in der Datei machine.config.
%systemroot%\Microsoft.NET\Framework\v1.0.3705\CONFIG
Die Versionsnummer, unterstrichen dargestellt, muss gegebenen-
falls an Ihre Installation angepasst werden.
type="Microsoft.VisualBasic.VBCodeProvider, É
System, Version=1.0.3300.0, É
Culture=neutral, É
PublicKeyToken=b77a5c561934e089"/>
<compiler language="js;jscript;javascript"
extension=".js"
type="Microsoft.JScript.JScriptCodeProvider,É
Microsoft.JScript, É
Version=7.0.3300.0, É
Culture=neutral, É
PublicKeyToken=b03f5f7f11d50a3a"/>
</compilers>
</compilation>
E debug="true|false"
Legt fest, ob der Compiler (Debuggercode) erzeugen soll oder
nicht. Debuggercode fhrt im Code Marken mit, mit denen die
Position der Haltepunkte in der Quelle festgestellt werden
kann. Das macht den Code langsamer und gr"ßer, ist aber in
der Entwicklungsphase notwendig. Die Option kann durch
ein Attribut der Seitendirektive @Page berschrieben werden.
E defaultLanguage="cs|vb|js"
Dies ist die Standardsprache, die in ASP.NET-Seiten fr einge-
betteten Code verwendet werden soll. Auch dieser Wert kann
mit der Seitendirektive @Page berschrieben werden. Der Stan-
dardwert ist »vb« fr Visual Basic .NET.
E tempDirectory
Die temporren Dateien werden normalerweise in folgendem
Pfad abgelegt:
%systemroot%\Microsoft.NET\Framework\v1.0.3705\Temporary
ASP.NET files\
Der unterstrichene Teil muss der installierten Version entspre-
chen. Temporre Dateien entstehen, wenn der Compiler
ASP.NET-Dateien bersetzt.
Sandini Bib
968 10 Konfiguration, Optimierung und Sicherheit
E strict="True|False"
Schaltet die Strict-Option (Option Strict) in VB.NET ein oder
aus. Standard ist »ein« (True).
E explicit="True|False"
Schaltet die Explicit-Option (Option Explicit) in VB.NET ein
oder aus. Standard ist »ein« (True).
E batch="True|False"
Kontrolliert die Verfgbarkeit der ?bersetzung von Stapelver-
arbeitungsdateien. Diese Option ist standardmßig aktiv.
E batchTimeout="15"
Wenn mehrere ?bersetzungsvorgnge aus einer Stapelver-
arbeitungsdatei heraus erfolgen, begrenzt diese Option die An-
zahl Sekunden, die der Vorgang in Anspruch nehmen darf.
Der Standardwert betrgt 15 Sekunden.
E maxBatchSize="1000"
Kontrolliert die maximale Zahl an Datenquellen, die in einem
Batchlauf verwendet werden k"nnen. Der Standardwert be-
trgt 1.000.
E maxBatchGeneratedFileSize="3000"
Bestimmt die maximale Dateigr"ße, die durch ?bersetzung in
einem Batchlauf entstehen darf. Der Standardwert betrgt
3.000 KByte.
E numRecompilesBeforeAppRestart="15"
Anzahl der Compilerlufe, nach der die Applikation recycelt
wird. Dies sichert die Zuverlssigkeit des Compilers.
Die Referenzen lassen sich aber auch im Visual Studio .NET hin-
zufgen, sodass die Option nur fr reine SDK-Umgebungen inte-
ressant ist.
Sandini Bib
Konfiguration des gesamten Systems machine.config 969
idleTime= Der Worker Process startet normalerweise bei der ersten eintref-
"Infinite fenden Anforderung und bleibt dann in mindestens einer Instanz
|HH:MM:SS"
bestehen. Der Standardwert fr das Attribut idleTime betrgt
Infinite. Wird hier ein Zeitwert eingesetzt, beendet der Worker
Process nach Ablauf der Zeit seine Arbeit und startet mit der
nchsten Anforderung wieder. Der Neustart entspricht dem
»Recyceln« des Prozesses. Auch hier ist die Anwendung gegeben,
wenn es Probleme mit steigendem Ressourcenverbrauch gibt.
shutDownTime- Der Worker Process hat normalerweise eine bestimmte Zeit zur
out="HH:MM:SS" Verfgung, um sich selbst zu beenden. Dieser Parameter – Stan-
dardwert fnf Sekunden – bestimmt diese Zeit. M"glicherweise
laufen sehr anspruchsvolle Anwendungen, die lngere Zeit brau-
chen, um Vorgnge abzuschließen und den Prozess spter enden
lassen. Dann kann die Zeit entsprechend erh"ht werden. Wird der
Zeitablauf erreicht, forciert ASP.NET das Ende des Prozesses ohne
Rcksicht auf den Zustand laufender ASP.NET-Programme.
Sandini Bib
Konfiguration des gesamten Systems machine.config 971
Der Neustart des Worker Processes spielt generell eine große Rol- requestLimit=
le, um hoch belastete Server stndig mit maximaler Leistung be- "Infinite|Zahl"
treiben zu k"nnen. Vor allem Provider, die viele ihnen unbekann-
te Applikationen laufen haben, profitieren von dieser Option. So
kann mit folgendem Parameter der Neustart nach 500 Anforde-
rungen forciert werden:
requestLimit="500"
Ein anderen Fall tritt auch unter hoher Last ab und zu auf. Wenn requestQueue-
zuviele Anforderungen anstehen, »stapelt« ASP.NET diese in ei- Limit="Zahl"
ner Warteschlange. Nun kann das hufig passieren und darauf
hindeuten, dass der Worker Process nicht mehr zufrieden stellend
arbeitet. Standardmßig drfen 5000 Anforderungen gestapelt
werden. Ist diese Zahl erreicht, wird der Prozess recycelt.
clientConnected- Mit einem weiteren Attribut kann das Verhalten des Clients ber-
Check="Infinite- wacht werden. Wenn die Verbindung zwischen Webserver und
|HH:MM:SS"
Browser langsam ist, kann es vorkommen, dass Benutzer die Seite
erneut anfordern, obwohl die vorhergehende Anforderung noch
nicht beendet wurde. Dann stapeln sich die Anforderungen in der
Anforderungswarteschlange. Standardmßig prft ASP.NET alle
fnf Sekunden, ob neue Anforderungen des Clients vorliegen.
Wenn das der Fall ist, wird nur die neueste bearbeitet, sodass die
Arbeit des Prozesses entlastet wird, weil sinnlose Anforderungen,
auf die ohnehin niemand mehr wartet, unbeantwortet bleiben.
E Wenn der seltene Fall eintritt, dass sich zwei Threads gegensei-
tig verriegeln (Deadlock), hilft responseDeadlockInterval. Dieses
Attribut legt fest, wann dies erkannt wird; der Standardwert
sind 3 Minuten (»00:03:00«). Mit responseRestartDeadlockInterval
wird festgelegt, wie lange nach einem Abbruch auf die nchste
Prfung gewartet wird (Standard: 9 Minuten (»00:09:00«).
E Zur Kontrolle der Threads des Worker Process dienen
maxWorkerThreads (maximale Anzahl, Standardwert 25) und
maxIoThreads (Ein-/Ausgabe-Threads, Standardwert ebenfalls
25).
10.5 Sicherheit
Dieser Abschnitt behandelt Sicherheit aus dem speziellen Blick-
winkel der Web-Applikation. Eine mehr allgemeine gehaltene
Einfhrung in die Sicherheitsprinzipien des Frameworks finden
Sie am Anfang des Buches im Abschnitt 1.6, »Allgemeine Sicher-
heit im Framework« ab Seite 83.
E Anonymer Zugriff
Diese Form erlaubt den Zugriff ohne weitere Einschrnkun-
gen. Der IIS gestattet dem Client die Nutzung des Systemkon-
tos IUSR_MachineName. Das gilt aber nur bis zum Aufruf des
ASP.NET-Worker Process. Alle .NET-Instanzen werden unter
dem ASP.NET-Konto ASPNET ausgefhrt.
E Authentifizierung mit Basic Authentication
Der Benutzer muss sich hier mit Benutzernamen und Kennwort
identifizieren. Beide Angaben werden im Klartext bertragen –
abgesehen von der blichen Base64-Kodierung fr binre Inhal-
te. Das Verfahren muss verwendet werden, wenn der geschtz-
te Zugriff beliebigen Clientprogrammen wie Netscape oder
Opera gestattet werden soll.
E Authentifizierung mit Digest Authentication
Dieses Verfahren erfordert auch die Angaben von Benutzer-
namen und Kennwort. Es wird aber nur ein Hashwert
(MD5-verschlsselt) bertragen, sodass ein Abfangen der
Kennwortdaten nicht ausreicht, um daraus die Daten zu re-
Sandini Bib
Sicherheit 975
E Windows-Authentifizierung
Siehe Abschnitt 10.5.5, »Windows-Authentifizierung« ab Seite
985.
E Forms-Authentifizierung
Siehe Abschnitt 10.5.3, »Forms-Authentifizierung« ab Seite
977.
E Passport
Bevor Sie sich daran machen, die Anmeldung ber Passport
zu realisieren, sollten Sie sich mit dem Konzept auseinander
setzen. Passport ist ein Dienst der Microsoft .NET My Services-
Palette und bietet Benutzern die M"glichkeit eines zentrales
Login fr alle teilnehmenden Webseiten. Das ist fr Benutzer
bequem und kostenlos. Fr Unternehmen sieht das freilich an-
ders aus. Sie mssen sich beim Passport-Dienst anmelden und
sich den Schlssel und Zugangscodes beschaffen, um daran
teilnehmen zu k"nnen. Dies ist in der Praxis eine lngere Pro-
zedur. Nach der Anmeldung mssen Sie eine »Compli-
ance«-Erklrung absenden und einem Tester bei Microsoft Zu-
gang zu Ihrer Applikation verschaffen. Nach erfolgreichem
Test wird Ihr Konto freigegeben und Sie nehmen nun mit Ihrer
Site an Passport teil.
Das Ganze macht Microsoft nicht aus Nchstenliebe. Da der
Dienst fr Benutzer kostenlos ist, stellt der Unternehmer die
Einnahmequelle dar. Zu bezahlen sind derzeit einmalig
$ 10.000 pro Unternehmen, auch wenn Sie mehrere Domnen
anschließen. Weiterhin fallen $ 1.500 fr jeden Compliance-
Test an, also am Anfang mindestens ein Mal. Danach behlt
sich Microsoft weitere Tests zu je $ 1.500 vor, wobei man mit
einem jhrlichen Rhythmus rechnen kann.
Sie sollten sich deshalb genau berlegen, ob der Aufwand fr
Passport lohnt. Fr eine Website mit hoher An- und Abmelde-
hufigkeit, starkem Endkundenverkehr und m"glicherweise
weiteren kostenpflichtigen Diensten kann der Einsatz lohnens-
wert sein. Die Autoren haben Erfahrung in der Realisierung
solcher Dienste und stehen interessierten Lesern hier gern im
Rahmen einer Consultingleistung zur Verfgung.
Der anonyme Daneben besteht natrlich immer die M"glichkeit, auf eine expli-
Zugriff zite Authentifizierung zu verzichten. Das ist im ?brigen auch die
Standardeinstellung: Der anonyme Zugriff. Der Prozess luft in
diesem Fall unter dem Konto ASPNET ab, solange die Impersoni-
Sandini Bib
Sicherheit 977
<configuration>
<system.web>
<authentication mode="Windows" />
...
</system.web>
</configuration>
Fr das Attribut mode k"nnen Sie folgende Werte whlen: Windows,
Passport, Forms, None. Innerhalb des Zweiges <system.web> k"nnen
dann feinere Einstellungen vorgenommen werden, die in den ent-
sprechenden Abschnitten weiter unten beschrieben werden.
10.5.3 Forms-Authentifizierung
Die Forms-Authentifizierung untersttzt die Entwicklung einer
eigenen Anmeldeprozedur basierend auf HTML-Formularen und
Cookies. Das Sicherheitsniveau ist relativ niedrig, außerdem muss
der Benutzer dauerhaft Cookies akzeptieren. Dafr ist der Ein-
richtungsaufwand gering. Die Datei web.config konfigurieren Sie
fr diese Funktion folgendermaßen:
Bleibt zuletzt die Festlegung der Benutzer, fr die die Authentifi-
zierung gilt, mit dem Tag <user>. Zwei Attribute sind hier zu fin-
den:
Sandini Bib
980 10 Konfiguration, Optimierung und Sicherheit
Die Reaktion auf die Eingabe kann wiederum auf zwei Aktionen
hinauslaufen: Freigabe der ursprnglich angeforderten Datei oder
Ausgabe eines Hinweises ber die misslungene Anmeldung. Bei-
des ist sehr einfach zu programmieren. Das Formular login.aspx
k"nnte folgendermaßen aussehen:
<h1>Anmeldung erforderlich</h1>
<form runat="server">
<table>
<tr>
<td>Name: </td>
<td>
<asp:TextBox Runat="server" ID="logName" />
</td>
</tr>
Sandini Bib
Sicherheit 981
<tr>
<td>Kennwort: </td>
<td>
<asp:TextBox TextMode="Password" É
Runat="server" ID="logPassword" />
</td>
</tr>
<tr>
<td></td>
<td>
<asp:Button Runat="server" ID="Submit" É
Text="Anmelden" É
OnClick="Login_Click"/>
</td>
</tr>
</table>
<asp:Label Runat="server" ID="LoginError"
BackColor="Red" ForeColor="White"/>
</form>
Listing 10.1: Ein Anmeldeformular (login.aspx)
Wenn nun eine geschtzte Datei angefordert wird, leitet ASP.NET Ablauf der
zu diesem Formular um. Sie erkennen dies durch die Vernde- Authentifizierung
rung des URL:
Imports System.Web.Security
Imports System.Web.Security
If (FormsAuthentication.Authenticate(logName.Text,
logPassword.Text)) Then
Wenn das der Fall ist, l"sen Sie eine Weiterleitung auf die ur-
sprnglich aufgerufene Seite aus:
Tipp: permanente Diese statische Methode bietet als zweiten Parameter die M"glich-
Cookies keit, das mit der Weiterleitung gesendete Authentifizierungs-Coo-
kie permanent zu speichern. Diese Wahl k"nnen Sie – im Sinne ei-
ner guten Benutzerfhrung – auch dem Benutzer berlassen.
Dazu k"nnten Sie ein CheckBox-Steuerelement auf der Anmeldesei-
Sandini Bib
Sicherheit 983
Ebenfalls statisch ist GetRedirectUrl. Beim Aufruf wird der URL GetRedirectUrl
zurckgegeben, der zur Weiterleitung verwendet wird. Sie k"n-
nen den Wert nicht ndern. Allerdings ist es natrlich m"glich, ei-
ne eigene Weiterleitung mit Response.Redirect (extern) oder
Server.Transfer (intern) auszufhren und auf die Dienste von Re-
directFromLoginPage zu verzichten.
Allerdings mssten Sie dann auch das Cookie selbst setzen. Dazu
kommt die statische Methode GetAuthCookie in Frage. Hiermit wird
ein Cookie-Objekt vom Typ HttpCookie erzeugt. Als Parameter ist
der Anmeldename des Benutzers und das Ablaufverhalten anzu-
geben. Das Ablaufverhalten wird als zweiter Parameter berge-
ben – True fr ein permanentes Cookie, False fr eines mit der de-
finierten Laufzeit. Sie k"nnen das Cookie nun verndern und
dann mit SetAuthCookie wieder setzen, sodass es von RedirectFrom-
LoginPage verarbeitet werden kann.
fernt. Ruft der Benutzer danach erneut die Seite auf, wird die An-
meldeprozedur erneut starten. Auch eine designierte Abmelde-
option geh"rt zu einer guten Benutzerfhrung.
10.5.4 Personalisierung
Ist die Authentifizierung gelungen, stehen weit mehr M"glichkei-
ten zur Verfgung als eine einfache Aussage ber die Zulassung
eines Kontos. So ist es sicher sinnvoll, einem Benutzer nach erfolg-
ter Anmeldung pers"nliche Dienste bereit zu stellen. Dies kann
auf jeder Seite anders aussehen. Sie ben"tigen also einen per-
manenten Zugriff auf die Authentifizierungsdaten innerhalb Ihrer
Programme.
Der Zugriff ist relativ einfach. Das folgende Beispiel zeigt eine
M"glichkeit. In der asxp-Seite gibt es ein Label-Steuerelement, das
hier zur Ausgabe verwendet wird:
Sandini Bib
Sicherheit 985
Imports System.Security
Imports System.Security.Principal
If (user.IsAuthenticated) Then
Footer.Text = "Willkommen, " + user.Name
Else
Footer.Text = "Oops. Noch unbekannt?"
End If
End Sub
End Class
Listing 10.3: Zugriff auf den authentifizierten Benutzer
(Ausschnitt aus SecurityCheck.aspx.vb)
Statt mit Formularen k"nnen Sie Benutzer auch ber ein regulres
Konto in der lokalen Benutzerverwaltung oder im Active Directo-
ry identifizieren. Dies drfte jedoch nur im Intranet praktikabel
sein. Lesen Sie im nchsten Abschnitt, wie es funktioniert.
10.5.5 Windows-Authentifizierung
Die Windows-Authentifizierung basiert auf der Prfung der An-
meldung mit Hilfe der NT-Benutzerverwaltung bzw. des Active
Directory. Zustzlich zur Aktivierung der Windows-Authentifi-
zierung selbst muss die Impersonifizierung aktiviert werden,
denn nur so gelangt der Anmeldedatenstrom ber den IIS bis zu
ASP.NET vor.
Sandini Bib
986 10 Konfiguration, Optimierung und Sicherheit
Fr den Benutzer gilt, dass bei dieser Form der Authentifizierung
das Standarddialogfeld des Browsers verwendet wird (Abbildung
10.6). Gestalterische Freiheiten wie bei der Forms-Authentifizie-
rung gibt es hier nicht.
Die Ressourcen mssen Sie, wenn Sie Windows die Kontrolle
berlassen, natrlich auch ber NTFS schtzen. Dazu rufen Sie
fr den betreffenden Dateien und Verzeichnisse den Eigenschaf-
ten-Dialog auf und tragen dort auf der Registerkarte Sicherheit
die Benutzer oder Gruppen ein, denen der Zugriff gewhrt wer-
den soll.
War die Anmeldung erfolgreich, k"nnen Sie hnlich wie bei der
Form-Authentifizierung auf die Anmeldeinformationen zugrei-
fen.
Imports System.Security.Principal
Den aktuell angemeldeten Benutzer k"nnen Sie wie schon bei der
Form-Authentifizierung dem Objekt User entnehmen. Das folgen-
de Beispiel zeigt das Prinzip:
Imports System.Text
Imports System.Security.Principal
Die Ausgabe hngt nun von den Einstellungen des IIS, der Sicher-
heitsbedingungen des angeforderten Objekts und dem verwende-
ten Namen ab. Die Arbeitsstation des Autors hieß zu diesem Zeit-
punkt »W2KWS«:
Sandini Bib
988 10 Konfiguration, Optimierung und Sicherheit
11 Besondere .NET-Klassen
11.1 Schnellstart
Dieser Abschnitt gibt einen kompakten ?berblick ber das Thema
und zeigt sinnvolle Verknpfungen mit ergnzenden und vorberei-
tenden Kapiteln. Der Wegweiser in die Referenz hilft, die passen-
den Seiten in der MSDN-Online-Referenz besonders schnell zu
finden.
Außerdem mssen Sie sicher stellen, dass wirklich nur Bilddaten ContentType
bertragen werden – HTML oder auch nur ein brig gebliebener
Zeilenumbruch mssen unbedingt vermieden werden.
Dynamische Bildauswahl
Als erstes Beispiel soll eine Gruppe von Bildern dynamisch aus-
gewhlt werden. Ideal ist dies fr einen grafischen Hitzhler, der
mit vorgefertigten Bilddateien arbeitet. Fr jede Ziffer wird eine
Bilddatei abgelegt; die Namen lauten 0.gif, 1.gif usw.
Der Zhler selbst wird hier nur simuliert – mit einem Zufallsgene-
rator:
<html lang="de">
<head>
<title>Dynamische Bilder</title>
</head>
<body>
<h1>Dynamische Bilder</h1>
<div id="zaehler" runat="server">
<asp:image id="d1" runat="server"/>
<asp:image id="d2" runat="server"/>
<asp:image id="d3" runat="server"/>
<asp:image id="d4" runat="server"/>
<asp:image id="d5" runat="server"/>
</div>
</body>
</html>
Listing 11.1: Anzeige eines grafischen Z=hlers (PixSelect.aspx)
Sandini Bib
992 11 Besondere .NET-Klassen
Catch e As FileNotFoundException
Response.ClearContent()
Response.ContentType = "text/html"
Response.Write ("Fehler: " + e.Message)
End Try
Response.End()
End Sub
</script>
Listing 11.3: Ausgabe der Bilddaten (PixSelectLade.aspx)
Das Programm beginnt mit der Festlegung des MIME-Typs der Wie es
?bertragung. Dazu wird die Seitendirektive @Page verwendet: funktioniert
Innerhalb der Methode Page_Load wird zuerst der Pfad zur passen-
den Bilddatei ermittelt:
Dann wird die Gr"ße der Datei ermittelt und nach Integer konver-
tiert:
Nun wird fr diese Datei ein Pufferspeicher erzeugt. Da Bilder Bi-
nrdaten sind, eignet sich ein Byte-Array dafr:
Nun kann die Datei komplett in den Puffer gelesen werden: Puffer f llen
fs.Read(puffer, 0, groesse)
fs.Close()
Sandini Bib
994 11 Besondere .NET-Klassen
Response.ClearContent()
Response.BinaryWrite(puffer)
<html lang="de">
<head>
<title>Dynamische Bilder</title>
</head>
<body>
<h1>Dynamische Bilder</h1>
<asp:image id="d5" runat="server" É
imageurl="PixDynamicLade.aspx?titel=Bilder
%20erstellen&text=Hallo, ich bin ein dynamisches Bild"/>
</body>
</html>
Listing 11.4: Aufruf des Grafikprogramms mit GET-Parametern (PixDynamic.aspx)
Wie es Das Programm ruft zuerst die GET-Parameter text und titel ab:
funktioniert
Dim text As String = Request.QueryString("text")
Dim titel As String = Request.QueryString("titel")
Bildgr?ße Dann wird zuerst ein Bitmap-Objekt erzeugt, das die Basisgr"ße
des Bildes festlegt:
Dim ob As Bitmap = New Bitmap(460,80)
Farben Fr die Ausgabe werden nun drei SolidBrush-Objekte erstellt, die
zum Zeichnen durchgehender Flchen ben"tigt werden und einen
Farbwert zugewiesen bekommen.
Dim pinselGruen As SolidBrush = New
SolidBrush(Color.FromArgb(0,80,0))
Dim pinselSchwarz As SolidBrush = New SolidBrush(Color.Black)
Dim pinselGelb As SolidBrush = New SolidBrush(Color.Yellow)
Fonts Als Farbwerte k"nnen Farbnamen oder die Methode FromArgb fr
RGB-Farbwerte genutzt werden. Color ist eine Struktur, die viel-
fltige Farbuntersttzung bietet, beispielsweise Konvertierungs-
methoden. Nach den Farben mssen die Fonts ausgewhlt wer-
Sandini Bib
Bilder dynamisch erstellen 997
Da die Texte mehr oder weniger lang sein k"nnen, wird nun die
tatschliche Gr"ße in Abhngigkeit von der gewhlten Schriftart
ermittelt:
Nun wird der Hintergrund gezeichnet – ein gelbes Rechteck, das Hintergrund
die gesamte Flche ausfllt:
Die Methode DrawString zeichnet nun den Text auf die Flche; an- Zeichenmethoden
gegeben werden die Zeichenkette, der Font, die Farbe und die
Platzierung der linken oberen Ecke in einem XY-Koordinatensys-
tem:
banner.DrawString
(titel, fontTitel, pinselSchwarz, É
230 - (titelGroesse.Width / 2), 8)
banner.DrawString (text, fontText, pinselGruen, É
230 - (textGroesse.Width / 2), 40)
Die Berechnung der X-Koordinate geht von der Hlfte des Ban-
ners aus (230 Pixel). Dann wird die Breite des Textes halbiert und
abgezogen; damit steht der linke Rand fest. Die H"he wird fest
vorgegeben. Natrlich kann auch dieser Wert leicht in Abhngig-
keit von der Schriftgr"ße berechnet werden, beispielsweise um
den Text vertikal zu zentrieren.
Der Rest des Programms dient nur der Ausgabe. Zuerst wird der
Ausgabepuffer geleert:
Response.ClearContent()
Dann wird das Bildobjekt mit der Methode Save direkt an den Ausgabe und
Ausgabedatenstrom bergeben. Die Methode erwartet außerdem Pixelformat
die Angabe des Typs der Grafik. Im Beispiel wird JPEG genutzt:
ob.Save(Response.OutputStream, ImageFormat.Jpeg)
Sandini Bib
998 11 Besondere .NET-Klassen
banner.Dispose()
ob.Dispose()
Response.End()
Cache An dieser Stelle sollten Sie brigens auch ber einen Cache fr dy-
namische Grafiken nachdenken. Informationen dazu bietet der
Abschnitt 8.7, »Optimierung des Datenverkehrs« ab Seite 809.
Parameter Bedeutung
w Breite (Width)
h H@he (Height)
ff Schriftartennamen (Font Face)
fs Schrifth@he in Punkt (Font Size)
c Farbe (Color)
bgc Hintergrundfarbe (Background Color)
bg Hintergrundbild (Background Image)
b Randbreite in Pixel (Border)
bc Randfarbe (Border Color)
Tabelle 11.1: Die Parameter des Programms zum dynamischen Erzeugen von Bildern
1 Fr hochfrequentierte Websites ist das sowieso keine besonders gute Idee.
Sandini Bib
Bilder dynamisch erstellen 999
Parameter Bedeutung
a Ausrichtung des Textes (Align)
t Der Text selber
type Das Bildformat (GIF; JPG etc.)
Tabelle 11.1: Die Parameter des Programms zum dynamischen Erzeugen von Bildern
(Forts.)
Ausgestattet mit diesen Informationen kann die Klasse auch zum
direkten Abruf aus einem <img>-Tag heraus genutzt werden.
Imports System.Drawing
Imports System.Drawing.Drawing2D
Imports System.Drawing.Imaging
Imports System.ComponentModel
Else
_align = "left"
End If
If Not Request.QueryString("t") Is Nothing Then
_text = Request.QueryString("t")
Else
_text = "No Text"
End If
If Not Request.QueryString("type") Is Nothing Then
_type = Request.QueryString("type")
Else
_type = "gif"
End If
If Not Request.QueryString("r") Is Nothing Then
_rotate = Convert.ToInt16(Request.QueryString("r"))
Else
_rotate = 0
End If
' build picture dynamically
' create bitmap
Dim oStringF As StringFormat = New StringFormat()
If (_rotate > 45 And _rotate < 135) É
Or (_rotate > 225 And _rotate < 315) Then
Dim _dummy As Int16 = _width
_width = _height
_height = _dummy
oStringF.FormatFlags É
= StringFormatFlags.DirectionVertical
End If
Dim oBM As Bitmap = New Bitmap(_width, _height)
Dim oG As Graphics = Graphics.FromImage(oBM)
Dim cc As ColorConverter = New ColorConverter()
oSB1 = New
SolidBrush(CType(cc.ConvertFromString(_bgcolor), É
System.Drawing.Color))
oSP1 = New Pen(CType(cc.ConvertFromString(_bordercolor), É
System.Drawing.Color))
oSB2 = New SolidBrush(CType(cc.ConvertFromString(_color), É
System.Drawing.Color))
Dim oF As Font = New Font(_fontface, CType(_fontsize,
Single))
oG.FillRectangle(oSB1, 0, 0, _width - _border, _height -
_border)
Dim oSF As SizeF = oG.MeasureString(_text, oF)
Dim oPF As PointF
Select Case _align
Case "center"
oStringF.Alignment = StringAlignment.Center
oPF = New PointF(_width / 2 - (oSF.Width / 2), É
Sandini Bib
1002 11 Besondere .NET-Klassen
Die Grafik- Die Bibliothek soll vor allem als Anregung fr eigene Experimente
funktionen dienen. Eine vollstndige Erluterung wrde weit in die Tiefen
von GDI+ fhren und dies hat nicht besonders viel mit ASP.NET
zu tun. Versuchen Sie nachzuvollziehen, wie die Ausgaben ver-
arbeitet werden. Konzentrieren Sie sich bei der Suche in der Refe-
renz auf die in der folgenden Tabelle aufgefhrten Klassen, die
die wichtigsten Ablufe beim Zeichnen von Bildern enthalten.
Sandini Bib
Bilder dynamisch erstellen 1003
Methoden Kurzbeschreibung
DrawLine Linien
DrawPolygon Polygone
DrawRectangle Rechtecke
DrawString Textausgabe
DrawImage Einbinden von Bildern
DrawArc Kreisb@gen
DrawBezier Kurven
DrawEllipse Ellipsen und Kreise
DrawGrid Gitter
DrawPie Ausgefllte Kreisform
End Class
Listing 11.7: So werden die Parameter bernommen und an die Bildklasse
weitergereicht (PictureClass.aspx.vb)
Hier wird nur eine Instanz der Klasse PictureClass erzeugt und
der Kontext an die entsprechende Eigenschaft bergeben. Der
Kontext enthlt die POST- und GET-Parameter, auf die dadurch
auch die nchste Klasse Zugriff hat. Mit dem Aufruf der Methode
ProcessPicture erscheint das Bild in dem durch JavaScript erzeug-
ten neuen Fenster.
Eine konkrete Anwendung der Klasse finden Sie in Abschnitt
12.2.3, »Programmierung eines eigenen Handlers« ab Seite 1031,
wo auf die hier gemachten Ausfhrungen Bezug genommen wird.
Sandini Bib
Bilder dynamisch erstellen 1005
Tipps Falls die Gefahr von Laufzeitfehlern sehr groß ist, sollten Sie die
Ausgabestrategie etwas .ndern. Statt den MIME-Typ global fest-
zulegen, k(nnen Sie diesen auch direkt als Eigenschaft ContentType
des Response-Objekts angeben:
Response.ClearContent()
Response.ContentType = "image/gif"
ob.Save(Response.OutputStream, ImageFormat.Jpeg)
Response.End()
Catch e As Exception
Response.ClearContent()
Response.ContentType = "text/html"
Response.Write ("Fehler: " + e.Message)
Response.End()
End Try
11.3.1 Vorbereitung
Fr den Versand von E-Mail sind einige vorbereitende Schritte
notwendig. Zuerst mssen Sie wissen, dass der E-Mail-Verkehr
im Internet ber so genannte SMTP-Server (SMTP = Simple Mail
Transfer Protocol) abgewickelt wird. Wenn ASP.NET eine E-Mail
versenden soll, muss ein solcher Server zur Verfgung stehen.
Wenn Sie derartige Programme auf einem lokalen Entwicklungs-
system testen, mssen Sie auch daran denken, dass eine Verbin-
dung zum Internet bestehen muss. SMTP basiert auf einer st.ndi-
gen Erreichbarkeit des jeweiligen Servers. Im Gegensatz dazu
arbeitet das Protokoll zum Abruf von E-Mail durch einen Client –
POP3 – nur auf Anforderung. Dies wird oft verwechselt. Sie befin-
den sich nun auf der »Serverseite« der E-Mail und mssen sich
mit den Gepflogenheiten bei SMTP auseinandersetzen.
E »Return-Path«
E »Received«
Sandini Bib
1008 11 Besondere .NET-Klassen
E »Date«
E »From«
E »Subject«
E »Sender«
E »To«
E »cc« usw.
E Return-path : route-addr
Pfad zurck zum Absender.
E Received : further-parameters
Fr further-parameters setzen Sie einen oder mehrere der
folgenden Parameter, jeweils zeilenweise getrennt, ein:
E [from domain]
Name des sendenden Computers
E [by domain]
Name des empfangenen Computers
E [via atom]
Physischer Pfad zu E-Mail.
E *(with atom)
Protokoll fr die Cbertragung.
E [id msg-id]
Nachrichten-ID des Empf.ngers.
E [for addr-spec] Formular.
E ; date-time
date-time ist die Empfangszeit.
E [Reply-To : address]
address muss mindestens ein Mal angegeben werden und
kann aus folgenden Elementen bestehen:
E From : mailbox
Absenderadresse (Autor).
Sandini Bib
Versenden von E-Mail via SMTP 1009
E Sender : mailbox
Sendeeinrichtung. Kann mit dem Autor identisch sein,
kann aber auch seinen Senderserver bezeichnen und
wird dann mit From kombiniert.
E [Resent-Reply-To : address]
Weiterleitungsinformation. Eine Angabe dazu kann aus
zwei Elementen bestehen. Das Element ist optional, address
besteht aus folgenden Elementen:
E Resent-Sender : mailbox
E Resent-From : mailbox
Weiterleitungsinformation mit Senderkennung und
Absenderdaten.
E Date : date-time
Sendedatum der Nachricht.
E Resent-Date : date-time
Zeitpunkt einer Weiterleitung.
E To : address
Prim.re Empf.ngeradresse. Mindestens eine Angabe muss
hier stehen. Erg.nzend k(nnen weitere Header folgen:
E Resent-To : address
Empf.nger einer Weiterleitung.
E cc : address
Kopie an weiteren Empf.nger (carbon copy)
E Resent-cc : address
Kopie einer Weiterleitung.
E bcc : address
Verdeckte Kopie (blind carbon copy)
E Resent-bcc : address
Verdeckte Kopie einer Weiterleitung.
E Message-ID : msg-id
Eindeutige ID des Empf.ngers.
E Resent-Message-ID : msg-id
Eindeutige ID einer Weiterleitung.
Sandini Bib
1010 11 Besondere .NET-Klassen
Das folgende Beispiel zeigt, wie die Header einer E-Mail aus-
sehen k(nnen. Die Mail entstammt einer Mailingliste. Die
Header sind fett hervorgehoben, die optionalen Attribute kur-
siv. Wegen des begrenzten Platzes pro Zeile wurden einige
Umbrche eingefgt, diese sind mit É gekennzeichnet. Gene-
rell beginnt auf jeder Zeile ein neuer Header, wenn der Text
in der ersten Spalte startet. Gut zu erkennen sind die vielen
zus.tzlichen, nicht RFC 822-konformen Header und der kom-
plexe Pfad, den diese E-Mail genommen hat (sicher auch pro-
voziert durch eine Weiterleitung):
Sandini Bib
Versenden von E-Mail via SMTP 1011
Return-path: <[email protected]>
Envelope-to: [email protected]
Delivery-date: Sat, 22 Apr 2000 00:31:15 +0200
Received: from [208.49.167.126] (helo=mb3.mailbank.com) É
by mx01.kundenserver.de with esmtp (Exim 2.12 #2) É
id 12ilw7-00007M-00 É
for [email protected]; Sat, 22 Apr 2002 00:30:47
+02 É
Received: from info.asp.net (MAIL.ASP.NET) É
by mb3.mailbank.com (8.9.1/8.9.1) with SMTP id
PAA29717 É
for ; <[email protected]> É
Fri, 21 Apr 2000 15:30:04 -0700
Received: (qmail 14450 invoked from network); 21 Apr 2000É
22:26:17 -0000
Received: from solix.wiso.uni-koeln.de ([email protected])
by solix.wiso.uni-koeln.de with SMTP; 21 Apr 2000 É
22:26:17 -0000
Received: from twdc.de (qmailr@[212.172.92.2])
by mail.asp.net (8.8.8/8.8.8) with SMTP id É
AAA14428 É
for <[email protected]>; Sat, 22 Apr 2000 00:26:10 +0200
Received: (qmail 20861 invoked from network); 21 Apr 2000 É
19:39:42 -0000
Received: from dialin126-nt.pg7.frankfurt.nikoma.de É
(HELO claudia) (213.54.38.126)
by 212.172.92.3 with SMTP; 21 Apr 2000 19:39:42
-0000
Message-ID: <001501bfabd2$188c6840$7e2636d5@claudia>
From: "Joerg Krause" <[email protected]>
To: <[email protected]> ASP.NET-LIST
References: <004501bfabac$e9c52800$d47c353e@n4n8u9> É
<[email protected]>
Subject:Re: [dotnet] EinfIhrung in ASP.NET
Date: Fri, 21 Apr 2000 20:50:37 +0200
Organization: Comzept GmbH
MIME-Version: 1.0
Content-Type: text/plain; charset="iso-8859-1"
X-Priority: 3
X-MSMail-Priority: Normal
X-Mailer: Microsoft Outlook Express 5.00.2014.211
X-MimeOLE: Produced By Microsoft
MimeOLE V5.00.2014.211
Reply-To: [email protected]
Sender: [email protected]
Sandini Bib
1012 11 Besondere .NET-Klassen
Errors-To: [email protected]
X-Mailman-Version: 1.0b8
Precedence: bulk
List-Id: deutschsprachige ASP.NET-Mailingliste É
<[email protected]>
X-BeenThere: <[email protected]>
Content-Transfer-Encoding: quoted-printable
X-MIME-Autoconverted: from 8bit to quoted-printable by É
mb3.mailbank.com id PAA29717
Listing 11.8: Header einer »gew4hnlichen« E-Mail aus einer Mailingliste
Imports System.Web.Mail
<html lang="de">
<head>
<title>Kontaktformular</title>
</head>
<body>
<h1>Kontaktformular</h1>
<form runat="server">
<table>
<tr>
Sandini Bib
Versenden von E-Mail via SMTP 1013
<td>Name</td>
<td>
<asp:textbox runat="server" id="name" É
width="250px"/>
<asp:requiredfieldvalidator runat="server" É
id="checkname" É
controltovalidate="name" É
display="dynamic">
<div style="color:red">
Geben Sie einen Namen ein</div>
</asp:requiredfieldvalidator>
</td>
</tr>
<tr>
<td>Anschrift</td>
<td>
<asp:textbox runat="server" id="anschrift" É
width="250px"/>
</td>
</tr>
<tr>
<td>Plz / Ort</td>
<td>
<asp:textbox runat="server" É
id="plz" width="50px"/>
<asp:textbox runat="server" É
id="ort" width="196px"/>
</td>
</tr>
<tr>
<td>Telefon</td>
<td>
<asp:textbox runat="server" id="telefon"/>
mit Vorwahl
</td>
</tr>
<tr>
<td>E-Mail</td>
<td>
<asp:textbox runat="server" É
id="email" width="250px"/>
</td>
</tr>
<tr>
<td>Anschrift</td>
<td>
<asp:textbox textmode="multiline" É
runat="server" É
id="nachricht" width="250px" É
Sandini Bib
1014 11 Besondere .NET-Klassen
height="100px"/>
</td>
</tr>
<tr>
<td colspan="2" align="right">
<asp:button runat="server" id="send"
text="Senden" onclick="SendMail"/>
</td>
</tr>
</table>
<asp:label runat="server" id="ergebnis"/>
</form>
</body>
</html>
Listing 11.9: Kontaktformular, das zum Versenden per E-Mail verwendet wird
(EmailForm.aspx)
Das Formular verfgt nur ber eine einfache Prfung des Na-
mens. Die gesamte Arbeit erledigt die Klasse Mail.
E-Mail versenden
Das Versenden ist weniger aufw.ndig als das Erstellen des For-
mulars:
Imports System.Web.Mail
+ ort.Text + vbCr
eMailText += "E-Mail : " + email.Text + vbCr
eMailText += "Telefon : " + telefon.Text + vbCr
eMailText += "Nachricht: " + vbCr
eMailText += nachricht.Text + vbCr + vbCr
eMailMessage.From = email.Text
eMailMessage.To = "[email protected]"
eMailMessage.Subject = "Kontaktformular ASP.NET"
eMailMessage.Body = eMailText
SmtpMail.SmtpServer = "smtp.kundenserver.de"
SmtpMail.Send(eMailMessage)
email = Nothing
ergebnis.Text = "Nachricht erfolgreich gesendet."
Catch e As Exception
ergebnis.Text = "FEHLER: " + e.Message
End Try
End Sub
End Class
Listing 11.10: Programm zum Versenden von Formulardaten per E-Mail
(EmailForm.aspx.vb)
Die Methode startet mit einem Try-Zweig. Das Versenden von Fehler abfangen
E-Mail kann an vielen Problemen scheitern; beispielsweise kann
der SMTP-Server nicht erreichbar sein, die Nachricht ablehnen,
Netzwerkfehler k(nnen st(ren usw. Alle Fehler werden mit einem
universellen Catch abgefangen.
Empfnger Dann wird der Empf.nger bestimmt. Tragen Sie hier die Adresse
ein, an die das Formular gesendet werden soll:
eMailMessage.To = "[email protected]"
Betreff Der Betreff kann auch festgelegt werden. Es ist sinnvoll, dies nicht
dem Benutzer zu berlassen, damit Sie die E-Mails vom Kontakt-
formular leicht erkennen k(nnen:
eMailMessage.Body = eMailText
Sollte der SMTP-Server des Providers mit einer Fehlermeldung der Art
t »Relaying prohibited« reagieren, wurden Sie nicht als autorisierter Be-
nutzer erkannt. Meist kann dies umgangen werden, indem unmittelbar
vorher eine autorisierte Abfrage des POP3-Servers erfolgt, also Post ab-
geholt wird.
Abbildung 11.7: Viel Formular und wenig E-Mail – der Versand geht eher still vor sich.
Wenn Sie die ersten Versuche an sich selbst senden, sollten Sie im
Postfach bald die entsprechenden Nachrichten vorfinden.
Abbildung 11.8: Nachricht in Outlook 2000, die mit dem Kontaktformular erzeugt wurde
Beachten Sie, dass das Versenden von Massenpost an Personen, mit de-
nen Sie nicht in einer laufenden Gesch.ftsbeziehung stehen, strafbar ist.
Verwenden Sie Rundschreiben nur, wenn der Benutzer sich vorher da-
mit einverstanden erkl.rt hat, beispielsweise durch Beitritt zu einer Mai-
lingliste oder einem Newsletter.
Dateianhnge Eine weitere Funktion betrifft Dateianh.nge. Dazu wird die Klas-
se MailAttachment eingesetzt. Es ist sehr einfach, die Anforderung
einer Datei per E-Mail mit ASP.NET zu programmieren:
HTML-Mails Die letzte Sonderfunktion betrifft HTML-Mails. Dazu ist nur eine
einzige Zeile Code hinzuzufgen:
eMailMessage.BodyFormat = Mailformat.Html
Soll der natrliche Weg verlassen werden und der Server zum System.Net
Browser mutieren, mssen andere Techniken Verwendung fin-
den. Die Basis bilden Klassen, die dem Namensraum System.Net
entstammen.
Beachten, Sie dass der Zugriff auf fremde Server dem eines Browsers .h-
nelt. Sie erhalten also niemals Zugang zu den programmierten Seiten
selbst, sondern nur zum fertigen HTML. Wenn Sie eine ASP.NET-Seite
abfragen, wird der fremde Server diese erst ausf5hren und Ihnen erst
dann das Ergebnis senden.
<h1>Webgrabbing</h1>
<h2>HTML-Code einer fremden Seite anschauen</h2>
<form id="WebGrabbing" method="post" runat="server">
http://<asp:TextBox Runat="server" ID="GrabUrl"/>
<asp:Button OnClick="Grab_Click" É
Runat="server" ID="Grab"/>
Sandini Bib
1020 11 Besondere .NET-Klassen
</form>
<pre>
<asp:Label Runat="server" ID="GrabbedSite"/>
</pre>
Listing 11.11: Erfassung einer URL und Platz f@r die Ausgabe (Relevanter Teil aus
WebGrabbing.aspx)
Wie blich wird die Arbeit in einer Code-Datei erledigt. Dort ist
die Ereignisbehandlungsmethode Grab_Click zust.ndig:
Imports System.IO
Imports System.Net
Imports System.Text
Imports System.Collections
Imports System.ComponentModel
Imports System.Data
Else
GrabbedSite.Text = "Textfeld darf nicht leer sein"
End If
End Sub
End Class
Listing 11.12: Grabben von Webseiten und Ausgabe des Inhalts (WebGrabbing.aspx.vb)
Dann wird sie ausgefhrt und der Zugriff auf den Eingangsdaten-
strom gew.hrt:
Dim wp As WebResponse = wr.GetResponse()
Mit dem StreamReader kann nun bequem auf die Daten zugegriffen
werden. Im Beispiel wird das benutzt, um die HTML-Codes zei-
lenweise auszugeben. Die Daten werden in einem StringBuilder-
Objekt gesammelt, das mit großen Zeichenketten effizienter um-
geht als eine einfache Zeichenkettenverknpfung:
Dim sb As StringBuilder = New StringBuilder()
Zu beachten ist bei der Angabe der Adresse, dass diese vollst.n-
dig, mit fhrendem »http://« angegeben werden muss.
Nach Code-Teilen Wollen Sie nun nach bestimmten Stellen in der Seite suchen, ver-
suchen wenden Sie am besten regul.re Ausdrcke. Diese werden in Ab-
schnitt 4.7, »Regul.re Ausdrcke« ab Seite 267 detailliert vor-
gestellt.
Das vorgestellte Beispiel ist in einer Beziehung noch unfertig: Wenn die
t Adresse nicht existiert, wird der Laufzeitfehler WebException ausgel:st.
Erweitern Sie das Programm selbstst.ndig um den erforderlichen Try-
Catch-Block.
Imports System.IO
Imports System.Net
Imports System.Net.Sockets
Imports System.Text
Imports System.Collections
Imports System.ComponentModel
= New StreamReader(tc.GetStream(), É
Encoding.ASCII)
Dim sb As StringBuilder = New StringBuilder()
Dim i As Integer = 0
While sr.Peek() <> EOF
sb.AppendFormat("{0,0:D3}: {1}<br/>", i,
sr.ReadLine())
i = i + 1
End While
WhoisResult.Text = sb.ToString()
tc.Close()
Catch ex As SocketException
WhoisResult.Text = "WHOIS-Fehler: " + ex.Message
End Try
End Sub
End Class
Listing 11.13: Abfrage des WHOIS-Servers des DENIC (WhoIsDotNet.aspx.vb)
Wie es Das Programm basiert auf einer neuen TCP-Verbindung (die IP-
funktioniert Ebene wird durch die Netzwerkkonfiguration des Servers be-
stimmt):
Dim tc As TcpClient = new TcpClient ()
tc.SendTimeout = 8000
s.Write(ba, 0, domain.Length)
Die Dekodierung erfolgt sofort nach ASCII, denn ein WHOIS- Dekodierung
Server sendet nur ASCII-Daten zurck.
Damit ist das Programm schon fertig; abschließend ein Blick auf
eine typische Ausgabe:
12 Servererweiterungen
12.1 Schnellstart
Dieser Abschnitt gibt einen kompakten Cberblick ber das Thema
und zeigt sinnvolle Verknpfungen mit erg.nzenden und vorbe-
reitenden Kapiteln. Der Wegweiser in die Referenz hilft, die pas-
senden Seiten in der MSDN-Online-Referenz besonders schnell zu
finden.
12.2 HTTP-Handler
ASP.NET verwendet generell so genannte Handler zur Abarbei-
tung der per HTTP eintreffenden Anfragen. Das sind Programme,
die sich innerhalb der Prozesskette fr bestimmte Aktionen zu-
st.ndig fhlen. Das gilt auch fr die fest implementierte Laufzeit-
umgebung. Durch die M(glichkeit, solche Handler selbst zu pro-
grammieren, ist es leicht, ASP.NET zu erweitern.
<configuration>
<system.web>
<httpHandlers>
<add verb="*" path="trace.axd"
type="System.Web.Handlers.TraceHandler"/>
<add verb="*" path="*.aspx"
type="System.Web.UI.PageHandlerFactory"/>
<add verb="*" path="*.ashx"
type="System.Web.UI.SimpleHandlerFactory"/>
<add verb="*" path="*.asmx"
type="System.Web.Services.Protocols.É
WebServiceHandlerFactory,
System.Web.Services, É
Version=1.0.3300.0, Culture=neutral, É
PublicKeyToken=b03f5f7f11d50a3a" É
validate="false"/>
<add verb="*" path="*.rem"
type="System.Runtime.Remoting.Channels.É
Http.HttpRemotingHandlerFactory, É
System.Runtime.Remoting, É
Version=1.0.3300.0, Culture=neutral, É
PublicKeyToken=b77a5c561934e089" É
validate="false"/>
<add verb="*" path="*.soap"
type="System.Runtime.Remoting.Channels.É
Http.HttpRemotingHandlerFactory, É
System.Runtime.Remoting, É
Version=1.0.3300.0, Culture=neutral, É
PublicKeyToken=b77a5c561934e089"
validate="false"/>
<add verb="*" path="*.asax"
type="System.Web.HttpForbiddenHandler"/>
<add verb="*" path="*.ascx"
type="System.Web.HttpForbiddenHandler"/>
<add verb="*" path="*.config"
type="System.Web.HttpForbiddenHandler"/>
<add verb="*" path="*.cs"
type="System.Web.HttpForbiddenHandler"/>
<add verb="*" path="*.csproj"
type="System.Web.HttpForbiddenHandler"/>
<add verb="*" path="*.vb"
type="System.Web.HttpForbiddenHandler"/>
<add verb="*" path="*.vbproj"
type="System.Web.HttpForbiddenHandler"/>
<add verb="*" path="*.webinfo"
type="System.Web.HttpForbiddenHandler"/>
<add verb="*" path="*.asp"
type="System.Web.HttpForbiddenHandler"/>
<add verb="*" path="*.licx"
Sandini Bib
1030 12 Servererweiterungen
type="System.Web.HttpForbiddenHandler"/>
<add verb="*" path="*.resx"
type="System.Web.HttpForbiddenHandler"/>
<add verb="*" path="*.resources"
type="System.Web.HttpForbiddenHandler"/>
<add verb="GET,HEAD" path="*"
type="System.Web.StaticFileHandler"/>
<add verb="*" path="*"
type="System.Web.HttpMethodNotAllowedHandler"/>
</httpHandlers>
</system.web>
</configuration>
Die Attribute Der Abschnitt ist relativ leicht lesbar. Verknpft wird eine Datei-
erweiterung (Attribut path) – optional auch ein konkreter Datei-
name mit oder ohne Platzhalterzeichen – mit einer Klasse, die fr
die Verarbeitung zust.ndig ist (Attribut type). Zus.tzlich kann
noch mit dem Attribut verb bestimmt werden, welche HTTP-Kom-
mandos akzeptiert werden. Außer dem Sternchen, das alle zu-
l.sst, k(nnen Sie hier GET, POST, DEBUG usw. einsetzen. Infor-
mationen zu HTTP finden Sie auch in Abschnitt 1.3.1, »Das
Protokoll HTTP« ab Seite 51.
dieser Eintrag noch nicht; Sie k(nnen ihn dann unterhalb des
Zweiges <system.web> anlegen.
E IsReusable
Diese Eigenschaft vom Typ Boolean gibt an, ob jede Anfrage ei-
ne neue Instanz des Handlers erfordert oder nicht. Der Stan-
dardwert, den diese schreibgeschtzte Eigenschaft zurckgibt,
ist True. Normalerweise existiert also nur eine Instanz fr alle
Anfragen. Wenn Sie keinen triftigen Grund haben, das Verhal-
ten zu .ndern, belassen Sie es dabei.
E ProcessRequest
Diese Methode erledigt die eigentliche Arbeit. Als Parameter
wird der Kontext der aktuellen Verbindung erwartet, Typ
Sandini Bib
1032 12 Servererweiterungen
Nun muss ASP.NET noch mitgeteilt werden, dass Sie unter be-
stimmten Umst.nden die Verwendung des eigenen Handlers
wnschen. Die »bestimmten Umst.nde« k(nnen anhand der Ver-
wendung einer bestimmten Dateierweiterung oder auch eines
konkreten Dateinamens erkannt werden.
Dateierweiterung Die Erkennung einer Dateierweiterung setzt voraus, dass diese
berhaupt bis zu ASP.NET vordringt. Dazu muss der IIS entspre-
chend instruiert werden. Gehen Sie dazu folgendermaßen vor:
F5r Windows XP-Benutzer: Klicken Sie nach der Auswahl des Pfa-
des nochmals in das Feld Ausfhrbare Datei, damit die OK-
Schaltfl.che aktiviert wird. Im .NET-Server und unter Windows
t
2000 ist das nicht erforderlich.
Damit ist der IIS nun in der Lage, Anfragen mit der Erweiterung
».pix« zu erkennen und an ASP.NET weiterzuleiten. Freilich kann
ASP.NET damit nichts anfangen, noch nicht. Die entsprechende
Verknpfung auf der »anderen Seite« wird in der Datei web.config
vorgenommen.
Praktische Programmierung
Bevor jedoch der Handler in der Datei web.config verknpft wird, Bilder dynamisch
muss eine Klasse erstellt werden, die die eigentliche Verarbeitung per Handler
erzeugen
vornimmt. Fr Standardaktionen existieren derartige Handler na-
trlich, die Verarbeitung von eigenen Erweiterungen mssen Sie
selbst programmieren. Im Beispiel geht es um das dynamische Er-
zeugen von Bildern. Eine Einfhrung in dieses Thema wurde be-
reits im Abschnitt 11.2, »Bilder dynamisch erstellen« ab Seite 990
gebracht. Es geht nun darum, ein Bild dynamisch zu erstellen, in-
dem als Bildpfad Folgendes verwendet wird:
<img src="bild.pix?text=Hallo%20Handler&color=red"/>
Dabei kommt es nur auf die Dateierweiterung an, der Name ist
beliebig und die aufgerufene Datei muss nicht existieren.
Sandini Bib
1034 12 Servererweiterungen
<body MS_POSITIONING="GridLayout">
<h1>Dynamische Bilder, mit Handler erzeugt</h1>
<img src="bild.pix?w=480&h=80&ff=Verdana&fs=28&a=center&b=2&bgc=
yellow&c=blue&t=Hallo%20Banner"/>
<br/>
<br/>
<br/>
<img src="bild.pix?w=48&h=48&ff=Tahoma&fs=10&bgc=black&b=0&
c=white&t=Mini"/><br/>
</body>
Listing 12.1: Der Aufruf der dynamisch erzeugten Bilder (PictureHandler.aspx)
Die Bedeutung der Parameter k(nnen Sie der Tabelle 11.1 entneh-
men. Freilich steckt das Know-how woanders. Die Klasse Picture-
Class finden Sie in Listing 11.6 im Abschnitt 11.2.3, »Eine kleine
Grafikbibliothek« ab Seite 998. Der Handler nutzt diese Klasse zur
Bilderzeugung. Er selbst wird als allein stehende Klassendatei
programmiert. Diese erzeugen Sie in Visual Studio .NET folgen-
dermaßen:
Get
Return True
End Get
End Property
End Class
Listing 12.2: Der komplette Handler zum dynamischen Erzeugen von Bildern implemen-
tiert die Schnittstelle IHttpHandler (PictureHandler.vb).
Auf die Aspekte der Grafikprogrammierung soll hier nicht erneut Wie es
eingegangen werden. Interessanter ist das Prinzip des Handlers, funktioniert
das auf der Nutzung der Schnittstelle IHttpHandler basiert.
Zugriff auf den Datenstrom von und zum Browser erhalten Sie IHttpHandler
ber den Parameter vom Typ HttpContext. Dieser wird an die Ei-
genschaft context der Zielklassen weitergeleitet. Die Entnahme der
Objekte Request und Response ist nicht zwingend erforderlich, wird
aber fr Ausgaben im Anwendungsfall ben(tigt. Sollte Ihr Hand-
ler nur eine Datenbank bedienen, k(nnen Sie darauf verzichten.
Bleibt noch die Eigenschaft IsReusable. Gibt diese True zurck,
wird nur eine Instanz der Klasse angelegt und immer wieder ver-
wendet. Das ist schneller, muss aber bei der Programmierung be-
achtet werden, denn so wird der Konstruktor nur einmal aufgeru-
fen. Wenn Ihr Handler verschiedene Sitzungen bedienen soll und
die Abfrage der Sitzungsdaten im Konstruktor erfolgt, wird das
nur funktionieren, wenn IsReusable den Wert False zurckgibt.
Das eigentliche Grafikprogramm wird in Abschnitt 11.2.3, »Eine
kleine Grafikbibliothek« ab Seite 998 genauer diskutiert.
Wenn Sie Zugriff auf den Server haben, k:nnen Sie die Einstellung auch
f5r alle Projekte in machine.config vornehmen.
<configuration>
<system.web>
<httpHandlers>
Sandini Bib
1036 12 Servererweiterungen
Der Handler soll nur auf HTTP-GET reagieren – dies wird durch
das Attribut verb bestimmt. Dann wird in path die Dateierweite-
rung verknpft. Sie k(nnen hier auch »bild.pix« schreiben, dann
ist die Wahl des Dateinamens nicht mehr frei. Bleibt als Letztes
noch das Attribut type. Hier ist der Name der Klasse mit vollst.n-
digem Namensraum und, durch Komma getrennt, der Name der
Assembly anzugeben.
<img src="pixx.aspx?w=480&h=80&ff=Verdana&fs=28&
a=center&b=2&bgc=yellow&c=blue&t=Hallo%20Banner"/>
...
<img src="pixx.aspx?w=48&h=48&ff=Tahoma&
fs=10&bgc=black&b=0&c=white&t=Mini"/><br/>
Listing 12.3: Aufruf des Handlers mit einem vollstEndigen Dateinamen und bekannter
Erweiterung (Ausschnitt aus PictureHandlerNoIIS.aspx)
Schon funktioniert der HTTP-Handler wieder und der IIS ist aus
dem Rennen. Das ber verschiedene Wege ein und derselbe
Handler verwendet wird, ist v(llig in Ordnung, denn auch die
standardm.ßigen Handler werden vielf.ltig genutzt.
12.3 HTTP-Module
HTTP-Module sind nicht an bestimmte Aufrufe oder die Ver-
knpfung mit einer Dateierweiterung gebunden. Sie agieren .hn-
lich wie die frheren ISAPI-Filter und beeinflussen den gesamten
Ein- und Ausgabedatenstrom. Das ist dann interessant, wenn Sie
globale Verhaltensweisen wnschen, aber nicht in bestehende Ap-
plikationen eingreifen m(chten.
Sandini Bib
1038 12 Servererweiterungen
Realisiert wird ein Modul, indem Sie eine Klasse schreiben, die
von der Schnittstelle IHttpModule ableitet. Sie mssen hier zwei
Methoden implementieren:
Ereignis Aktion
BeginRequest Start der Anforderung
AuthenticateRequest Authentifizierung (Benutzererkennung)
AuthorizeRequest Autorisierung (Rechtvergabe)
ResolveRequestCache Cache pr6fen
HTTP-Handler instanziieren
(die f6r die Seite (Page), aber auch eigene)
AcquireRequestState Status pr6fen
PreRequestHandlerExecute Vor der Anforderungsverarbeitung
HTTP-Handler ausf6hren
PostRequestHandlerExecute Nach der Ausf6hrung, Seite fertig
ReleaseRequestState Freigabe der Ressourcen
Aufruf von Ausgabefiltern
(siehe Response.Filter)
Sandini Bib
HTTP-Module 1039
Ereignis Aktion
UpdateRequestCache Cache aktualisieren
EndRequest Anforderung fertig, Daten senden
HTTP-Module sind also auch im Hinblick auf die Prozessver- HTTP-Module und
arbeitung sehr leistungsf.hig. Sie k(nnen n.mlich ihre Leistungen global.asax
zu jedem Zeitpunkt der Prozessverarbeitungskette anbieten. Ver-
gleichen Sie aber in diesem Zusammenhang auch die M(glichkei-
ten, die Eingriffe in die Datei global.asax bieten. Mehr dazu finden
Sie im Abschnitt 8.6.2, »Die Datei global.asax« ab Seite 808.
<configuration>
<system.web>
<httpModules>
<add type="Addison.VBNet.Advanced.CopyrightModule, É
vbnetadvanced" É
name="CopyrightModule"/>
</httpModules>
Das Attribut type nimmt den Namen der Klasse auf und – durch
Komma getrennt – den Namen der Assembly. Abbildung 12.2
zeigte bereits, wie Sie den Assemblynamen ermitteln k(nnen. In
name wird außerdem noch ein Name des Moduls vergeben. Emp-
fehlenswert ist es, den Klassennamen zu verwenden.
12.3.2 Anwendungsbeispiel
Als Beispiel soll hier gezeigt werden, wie Sie verdeckte Copy-
right-Informationen in alle gesendeten Seiten einfgen k(nnen:
Imports System
Imports System.Web
End Class
Listing 12.4: Ein HTTP-Modul (CopyrightModule.vb)
Wie es Aufgabe dieses Programm ist es, oberhalb und unterhalb jeder ge-
funktioniert sendeten Seite einen HTML-Kommentar einzufgen. Dazu wird
in der Methode Init zuerst eine Ereignisbehandlung fr den An-
fang der Anforderung definiert:
AddHandler app.BeginRequest, É
New EventHandler(AddressOf SendCopyrightBefore)
AddHandler app.EndRequest, É
New EventHandler(AddressOf SendCopyrightAfter)
Sandini Bib
HTTP-Module 1041
ha.Context.Response.Write(copyrightAfter)
13 Webservices
Webservices sind fr die meisten Entwickler erst seit kurzem ein
Thema. W.hrend Microsoft sie hartn.ckig als Technologie der Zu-
kunft propagiert, bleiben Anwendungen rar. Dies k(nnte sich .n-
dern, denn mit .NET ist es sehr einfach, auch komplexe Web-
services zu programmieren. Dies gilt fr beide Varianten, die
Nutzung eines fremden Webservices ebenso wie das Anbieten ei-
nes eigenen.
13.1 Schnellstart
Dieser Abschnitt gibt einen kompakten Cberblick ber das Thema
und zeigt sinnvolle Verknpfungen mit erg.nzenden und vorberei-
tenden Kapiteln. Der Wegweiser in die Referenz hilft, die passen-
den Seiten in der MSDN-Online-Referenz besonders schnell zu
finden.
Dabei ist es nicht so schwer, sich Dienste zu berlegen und der ver-
h.ltnism.ßig geringe Aufwand, einen Webservice zu erstellen,
drfte die Hemmschwelle sehr niedrig legen. In diesem Kapitel
werden zwei Varianten der Webservices vorgestellt. Einmal die
Konsumierung eines fremden Dienstes am Beispiel der Such-
maschine Google. Dies erfolgt einmal unter Einsatz des Werkzeugs
wsdl.exe, mit dem aus der den Dienst beschreibenden WSDL-Datei
eine Proxyklasse erstellt werden kann. Die andere Variante zeigt,
wie die WSDL-Informationen programmtechnisch extrahiert und
verwertet werden ohne dass wsdl.exe ben(tigt wird.
Zum anderen wird das Anbieten eines eigenen Webservices be-
handelt. M(gliche Einsatzf.lle sind Partnerprogramme oder ein-
fach praktische Dienstleistungen fr andere Serveranwendungen.
13.2 Grundlagen
Ein Grundverst.ndnis fr Webservices erh.lt man, wenn die Kom-
munikationswege gekl.rt sind. So findet die Kommunikation zwi-
schen dem Anbieter des Webservice und dem Client (hier Consu-
mer genannt) auf Serverebene statt. Es geht also nicht unbedingt
darum, Benutzern einen Webservice zur Verfgung zu stellen, son-
dern bestenfalls darum, diesen die Leistungen mit einem Webinter-
face zug.nglich zu machen. Aber auch das drfte der Ausnahme-
fall sein.
Die Protokolle Wenn Server miteinander reden k(nnen – ohne menschliches
Zutun – ist das ein wenig Science Fiction und in Zukunft ein starkes
Gesch.ft. Denn die Kommunikation wird durch die zugrunde lie-
genden Technologien, XML, SOAP, HTTP, WSDL usw. so billig
und einfach, dass sie in der Breite zur Anwendung gelangen k(n-
nen. Das ist der Unterschied zu frher, wo es Serverkommunikati-
on auch schon gab, diese sich aber auf wenige Anwendungen
beschr.nkte. Denkbar sind vor allem Partnernetzwerke, von der
Bannerschaltung ber einen gemeinsamen Ad-Server bis hin zu
den beliebten Webringen. Egal, ob Sie Artikel verkaufen und Sub-
unternehmer suchen oder als Sammelshop auf mehrere Lieferanten
zugreifen m(chten, Webservices sind die ideale Kommunikations-
Sandini Bib
Grundlagen 1045
Abbildung 13.1: Ablauf des entfernten Funktionsaufrufes aus Sicht der Protokollschichten
Auch wenn hier nicht weiter darauf eingegangen wird, sollten Sie wis-
sen, dass SOAP nicht zwingend mit HTTP verkn5pft ist. Als Transport-
protokolle k:nnen auch HTTPS (verschl5sseltes HTTP) und SMTP
(E-Mail) auftreten. Prinzipiell schreibt der Standard 5berhaupt kein
Protokoll vor. Es muss nur in der Lage sein, XML-Daten zu 5bertragen.
Sandini Bib
1046 13 Webservices
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<SOAP-ENV:Header>
: : :
</SOAP-ENV:Header>
<SOAP-ENV:Body>
: : :
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Hier wird bereits deutlich, dass als zus.tzlicher Namensraum un- Datentypen
ter anderem »xsd« verwendet wird, die XML Schema Definition
Language (XSD). Die dort definierten Datentypen bilden damit
das Rckgrat der typstrengen Cbermittlung von Daten zwischen
den Kommunikationspartnern.
Das Wurzelelement bildet der so genannte SOAP-Envelope, auf
deutsch der Umschlag. Der URI des Namensraumes lautet immer
wie folgt:
http://schemas.xmlsoap.org/soap/envelope/
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/1999/XMLSchema">
<SOAP-ENV:Body>
<ns1:doGoogleSearch xmlns:ns1="urn:GoogleSearch"
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/
encoding/">
<key xsi:type="xsd:string">00000000...0000000000</key>
<q xsi:type="xsd:string">shrdlu winograd maclisp
teletype</q>
<start xsi:type="xsd:int">0</start>
<maxResults xsi:type="xsd:int">10</maxResults>
<filter xsi:type="xsd:boolean">true</filter>
<restrict xsi:type="xsd:string"></restrict>
<safeSearch xsi:type="xsd:boolean">false</safeSearch>
<lr xsi:type="xsd:string"></lr>
<ie xsi:type="xsd:string">latin1</ie>
<oe xsi:type="xsd:string">latin1</oe>
</ns1:doGoogleSearch>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Listing 13.1: Eine SOAP-Nachricht, hier eine Anfrage an den Suchdienst Google
(aus dem Google-API-Paket)
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" É
xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance" É
xmlns:xsd="http://www.w3.org/1999/XMLSchema">
<SOAP-ENV:Body>
<ns1:doGoogleSearchResponse xmlns:ns1="urn:GoogleSearch" É
SOAP-ENV:encodingStyle=
"http://schemas.xmlsoap.org/soap/encoding/">
<return xsi:type="ns1:GoogleSearchResult">
<documentFiltering xsi:type="xsd:boolean">
false</documentFiltering>
<estimatedTotalResultsCount xsi:type="xsd:int">
3</estimatedTotalResultsCount>
<directoryCategories É
xmlns:ns2="http://schemas.xmlsoap.org/soap/encoding/" É
xsi:type="ns2:Array" v
ns2:arrayType="ns1:DirectoryCategory[0]">
</directoryCategories>
Sandini Bib
Grundlagen 1049
<searchTime xsi:type="xsd:double">
0.194871</searchTime>
<resultElements
xmlns:ns3="http://schemas.xmlsoap.org/soap/encoding/"
xsi:type="ns3:Array"
ns3:arrayType="ns1:ResultElement[3]">
<item xsi:type="ns1:ResultElement">
<cachedSize xsi:type="xsd:string"> É
12k</cachedSize>
<hostName xsi:type="xsd:string"></hostName>
<snippet xsi:type="xsd:string">É
... Hier steht der Antworttext dieser Abfrage ...
</snippet>
<directoryCategory É
xsi:type="ns1:DirectoryCategory">
<specialEncoding xsi:type="xsd:string"> É
</specialEncoding>
<fullViewableName xsi:type="xsd:string"> É
</fullViewableName>
</directoryCategory>
<relatedInformationPresent É
xsi:type="xsd:boolean">
true
</relatedInformationPresent>
<directoryTitle É
xsi:type="xsd:string"></directoryTitle>
<summary xsi:type="xsd:string"></summary>
<URL xsi:type="xsd:string"> É
... http://die_url_der_suchanfrage ...
</URL>
<title xsi:type="xsd:string">...Titel...</title>
</item>
<item>...</item>
</resultElements>
<endIndex xsi:type="xsd:int">3</endIndex>
<searchTips xsi:type="xsd:string"></searchTips>
<searchComments xsi:type="xsd:string"> É
</searchComments>
<startIndex xsi:type="xsd:int">1</startIndex>
<estimateIsExact xsi:type="xsd:boolean"> É
true</estimateIsExact>
<searchQuery xsi:type="xsd:string"> É
shrdlu winograd maclisp teletype</searchQuery>
</return>
</ns1:doGoogleSearchResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Listing 13.2: Eine SOAP-Antwort, die <item>-Elemente w@rden sich in der Praxis wieder-
holen.
Sandini Bib
1050 13 Webservices
SOAP-Praxis Nun erscheint der Umgang mit SOAP nicht besonders einfach.
Trotz leistungsf.higer XML-Funktionen in .NET w.re einiger Pro-
grammieraufwand n(tig, die Nachrichten in jeder Situation exakt
zu formulieren und die Antwort entsprechend auszuwerten. Vor
allem dann, wenn der Anbieter die Struktur seines Dienstes .n-
dert, wird es problematisch, denn dann muss das eigene Pro-
gramm ge.ndert oder schlimmstenfalls neu geschrieben werden.
Da sich Anbieter und Konsument eines Webservices nicht kennen
mssen und vermutlich oft geografisch weit auseinander sitzen,
sind weitere Schritte hin zur praktischen Nutzbarkeit notwendig.
Auch WSDL basiert auf XML. Die prinzipielle Struktur und die
Abh.ngigkeiten der Elemente zeigt in vereinfachter Form die Ab-
bildung 13.3.
<definitions name="urn:GoogleSearch"
targetNamespace="urn:GoogleSearch"
xmlns:typens="urn:GoogleSearch"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns="http://schemas.xmlsoap.org/wsdl/">
<types> </types>
<message name="MessageName">
<part name="parameter" type="xsd:string"/>
<part name="parameter" type="xsd:string"/>
</message>
<portType name="PortName">
<operation name="Operation">
Sandini Bib
1052 13 Webservices
<input message="typens:TypDefinition"/>
<output message="typens:TypDefinition"/>
</operation>
</portType>
transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="OperationName">
<soap:operation soapAction="urn:ActionName"/>
<input>
<soap:body use="encoded"
namespace="urn:ActionName"
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
</input>
<output>
<soap:body use="encoded"
namespace="urn:ActionName"
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
</output>
</operation>
</binding>
<service name="ServiceName">
<port name="PortName" binding="typens:BindingName">
<soap:address location="http://url_des_dienstes.de"/>
</port>
</service>
</definitions>
Listing 13.3: WSDL-Datei des Google-Webservice
Diese Struktur l.sst sich gut in einer Klasse abbilden, die dann im
Programm verwendet wird. Eine solche Klasse wird als Proxy-
Klasse bezeichnet.
Das Prinzip der Discovery-Dateien (DISCO) ist eine Erfindung von Mi-
crosoft. Alternativ dazu hat IBM das ADS (Advertisment and Discovery
Protocol) entwickelt, das vergleichbare Aufgaben 5bernimmt. Vermut-
lich wird sich am Ende eine Mischung aus beiden durchsetzen, wie es
schon bei WSDL der Fall war, das auch aus zwei konkurrierenden Stan-
dards entstand.
Abbildung 13.4: Nutzung von UDDI f@r die automatische Ermittlung von Webservices
Bevor Sie mit Google arbeiten, m5ssen Sie sich einen Lizenzschl5ssel be-
schaffen. Derzeit kann Google bis 1.000 Mal pro Tag abgefragt werden.
Pro Anfrage sind maximal zehn Antworten m:glich. Die Nutzung ist
kostenlos, Informationen 5ber ein kommerzielles Modell, das eine inten-
sivere oder kommerzielle Nutzung erlaubt, waren Anfang 2003 noch
nicht verf5gbar.
<portType name="GoogleSearchPort">
<operation name="doGetCachedPage">
<input message="typens:doGetCachedPage"/>
<output message="typens:doGetCachedPageResponse"/>
</operation>
<!-- ... -->
</portType>
<message name="doGoogleSearch">
<part name="key" type="xsd:string"/>
<part name="q" type="xsd:string"/>
<part name="start" type="xsd:int"/>
<part name="maxResults" type="xsd:int"/>
<part name="filter" type="xsd:boolean"/>
<part name="restrict" type="xsd:string"/>
<part name="safeSearch" type="xsd:boolean"/>
<part name="lr" type="xsd:string"/>
<part name="ie" type="xsd:string"/>
<part name="oe" type="xsd:string"/>
</message>
<message name="doGoogleSearchResponse">
<part name="return" type="typens:GoogleSearchResult"/>
</message>
Dienstname Einsatzzweck
doGoogleSearch Standardsuche, ben=tigt die in Tabelle 13.2
gezeigten Parameter
doSpellingSuggestion Korrekturvorschlag f6r Schreibfehler anfordern.
Parameter: key und phrase
doGetCachedPage Suche im Google-Cache. Parameter: key und url
Suchform Beschreibung
+wort Wort muss vorkommen
-wort Wort darf nicht vorkommen
"Eine Phrase" Exakte /bereinstimmung
Suchform Beschreibung
Wort1 OR Wort2 Wort1 oder Wort2 m6ssen vorkommen. Die
UND-Verkn6pfung wird standardm1ßig verwendet
site: Die angegebene URL wird durchsucht
<html>
<head><title>GoogleLinks</title></head>
<body MS_POSITIONING="GridLayout">
<h1>Unsere Linkliste</h1>
<asp:PlaceHolder Runat="server" ID="LinkListe"/>
</body>
</html>
Listing 13.4: Die Vorlage f@r die Linkliste (GoogleLinks.aspx)
wsdl.exe Damit die Abfrage der Daten per SOAP funktioniert, wird eine
von SoapHttpClientProtocol abgeleitete Klasse ben(tigt. Diese wird
als Proxy-Klasse bezeichnet, weil sie eine Art Schnittstelle zum
Dienst darstellt. Damit das nicht zu kompliziert wird, befindet
sich im Framework SDK das Werkzeug wsdl.exe. Verfgt der
Dienst ber eine WSDL-Datei, erstellt dieses Programm auto-
matisch die Proxy-Klasse. Haben Sie die WSDL-Datei aus dem
Google-API-Kit bereits auf der Festplatte, erstellen Sie die Klasse
mit folgendem Aufruf auf der Visual Studio .NET-Befehlszeile:
Wenn Sie mit Visual Studio .NET-Projekten und VB.NET arbeiten, Umgang mit dem
wird normalerweise in den Standardeinstellungen des Projekts Namensraum
ein zentraler Namespace festgelegt. Wenn Sie nun die Klassen er-
stellen und einen Namensraum angeben und diese Klasse dann
dem Projekt hinzufgen, »verdoppelt« sich quasi der reale Name
des Namensraumes. Das funktioniert natrlich nicht. Lassen Sie
deshalb wie beschrieben die Angabe des Namensraumes beim
Aufruf des Tools wsdl weg, auch wenn andere Quellen dies so
nicht beschreiben. C# verh.lt sich an dieser Stelle brigens anders
und die meisten Beispiele im Internet sind dafr ausgelegt. Den-
noch k(nnen alle Funktionen auch mit VB.NET programmiert
werden.
Imports System.Web.Services
Imports System.Web.Services
Else
l.Text = "Leider gab es keine Treffer"
LinkListe.Controls.Add(l)
End If
End Sub
End Class
Listing 13.5: Erstellung der Linkliste mit Hilfe des Google-Webservices
(GoogleLinks.aspx.vb)
Bevor Sie das Programm bei sich starten, mssen Sie sich von
Google den am Anfang erw.hnten Lizenzschlssel beschaffen
und statt der XX-Reihe im Listing eintragen (Variable gKey). Auf
einem Entwicklungssystem ist außerdem natrlich eine Internet-
verbindung notwendig. Eine Firewall ist kein Problem, da als
Transportprotokoll nur HTTP (Port 80) verwendet wird.
Wie es Der Ablauf beginnt mit der Instanziierung der Proxy-Klasse (der
funktioniert Name ist durch Webservice selbst festgelegt, kann also nicht ge.n-
dert werden):
Das Ergebnis der Abfrage wird von der Methode bestimmt, die
aufgerufen wird. Fr die Standardfunktion doGoogleSearch hat dies
den Typ GoogleSearchResult. Die Parameter werden durch die De-
finition in der WSDL-Datei bestimmt:
GoogleSearchResult GoogleResult = É
Google.doGoogleSearch É
(gKey, gQ, gStart, gMaxResults, É
false, "", false, "lang_de", "", "")
Sandini Bib
Webservices konsumieren 1063
Falls nun Ergebnisse ermittelt wurden, kann dies durch den Ant-
wortparameter resultElements ermittelt werden:
Der Hyperlink wird nun mit der URL und dem Text versorgt:
hl.NavigateUrl = GoogleResult.resultElements(i).URL
hl.Text = GoogleResult.resultElements(i).title
LinkListe.Controls.Add(hl)
LinkListe.Controls.Add(gcBreak)
GoogleServices.DataSource = gWsdl.PortTypes(0).Operations
GoogleServices.DataTextField = "Name"
GoogleServices.DataBind()
Fgt nun Google mehr Dienste hinzu, verl.ngert sich die Liste au-
tomatisch, auch ohne den Einsatz von wsdl.exe. Auf Basis der ge-
troffenen Auswahl soll nun ein Formular entworfen werden, das
exakt nach der Gestaltung der Eingabedaten erzeugt wird. Dazu
definiert WSDL fr jede Operation eine so genannte »Message«,
und zwar eine fr die Eingabe (Input, zum Aufruf der Funktion)
und eine fr die Ausgabe (Output, der Rcklauf vom Dienst). Diese
Definition bildet auch die Basis fr die Gestaltung der SOAP-
Nachricht. Im Beispiel wird die Operations-Kollektion durchlau-
fen, um die Auswahl zu ermitteln. Dann besteht Zugriff auf den
Eingabetyp:
Etwas schwieriger ist der Start der Anfrage selbst, denn nun wer-
den nicht nur die Informationen aus der WSDL-Datei ben(tigt,
wie fr die Erstellung des Formulars, sondern die gesamte Proxy-
Klasse.
sdi.ProtocolName = "Soap";
sdi.Import (cn, null);
CSharpCodeProvider cscp = new CSharpCodeProvider ();
ICodeGenerator icg = cscp.CreateGenerator ();
StringBuilder sb = new StringBuilder ();
StringWriter sw = new StringWriter (sb);
icg.GenerateCodeFromNamespace (cn, sw, null);
sw.Close ();
CompilerParameters cp = new CompilerParameters ();
cp.ReferencedAssemblies.Add ("System.dll");
cp.ReferencedAssemblies.Add ("System.Data.dll");
cp.ReferencedAssemblies.Add ("System.Xml.dll");
cp.ReferencedAssemblies.Add ("System.Web.Services.dll");
cp.GenerateExecutable = false;
cp.GenerateInMemory = false;
cp.OutputAssembly = AssemblyFile;
cp.IncludeDebugInformation = false;
ICodeCompiler icc = cscp.CreateCompiler ();
cr = icc.CompileAssemblyFromSource (cp, sb.ToString ());
if (cr.Errors.Count > 0)
{
throw new Exception É
(String.Format("{0} Fehler beim kompilieren", É
cr.Errors.Count));
}
}
}
Listing 13.6: Dynamischer Compiler zum Dbersetzen der WSDL-Datei in eine
Proxyklasse
cp.ReferencedAssemblies.Add ("System.dll");
Dann wird bestimmt, dass die Assembly als Datei und als nicht
ausfhrbar erzeugt wird. Der Dateiname bestimmt, wo die As-
sembly landet:
1 Die Wahl der Sprache erfolgte auch aus demonstrativen Grnden, ebenso-
gut w.re VB.NET in der Lage, die Aufgabe zu erfllen. Der Aufruf des
C#-Compilers zeigt die Interoperabilit.t in .NET, denn die Verwendung er-
folgt sp.ter mit VB.NET.
Sandini Bib
Webservices konsumieren 1067
cp.OutputAssembly = AssemblyFile;
string AssemblyFile =
System.Web.HttpContext.Current.Server.MapPath
(System.Web.HttpContext.Current.Request.ApplicationPath+@
"\bin\WdslAssembly.dll");
Mit diesen Daten kann nun kompiliert werden. Dazu wird ein vir-
tueller Compiler erzeugt:
Damit das verwendet werden kann, ist nun noch einiger Auf-
wand n(tig. Ein Blick auf das Ergebnis zeigt, dass es sich lohnt.
Zuerst das automatisch aus den WSDL-Daten erzeugte Formular:
Imports System.IO
Imports System.Text
Imports System.Reflection
Imports System.CodeDom
Imports System.CodeDom.Compiler
Imports System.Xml
Imports System.Xml.Schema
Imports System.Web.Services
Imports System.Web.Services.Description
Imports System.Web.Services.Protocols
Imports System.Collections
Imports System.ComponentModel
Imports System.Data
Imports Microsoft.VisualBasic
CompilerParameters()
cp.ReferencedAssemblies.Add("System.dll")
cp.ReferencedAssemblies.Add("System.Data.dll")
cp.ReferencedAssemblies.Add("System.Xml.dll")
cp.ReferencedAssemblies.Add("System.Web.Services.dll")
cp.GenerateExecutable = False
cp.GenerateInMemory = False
cp.OutputAssembly = AssemblyFile
cp.IncludeDebugInformation = False
Dim icc As ICodeCompiler = cscp.CreateCompiler()
cr = icc.CompileAssemblyFromSource(cp, sb.ToString())
If cr.Errors.Count > 0 Then
Throw New Exception(String.Format("{0} Fehler
beim kompilieren", cr.Errors.Count))
End If
End If
End Sub
End Class
currentOutputMessage.Parts("return").Type.Name
Case "string"
If Not GoogleResult Is Nothing Then
GoogleResultStream.Text =
GoogleResult.ToString()
Else
GoogleResultStream.Text = "Kein Ergebnis
gefunden"
End If
Case "base64Binary"
Dim encEncoder As System.Text.Encoding =
System.Text.ASCIIEncoding.ASCII
GoogleResultStream.Text =
encEncoder.GetString(CType(GoogleResult, System.Byte()), 0,
CType(GoogleResult, System.Byte()).Length)
Case Else
' any user defined type ?
If Not GoogleResult Is Nothing Then
Dim o As Object =
Activator.CreateInstance(myGoogle.currentType)
Dim subo As Object
o = Convert.ChangeType(GoogleResult,
myGoogle.currentType)
Dim r As Object
Dim subr() As Object
Dim t As Table = New Table()
t.BorderStyle = BorderStyle.Solid
t.GridLines = GridLines.Both
t.BorderWidth = Unit.Pixel(1)
Dim fi As FieldInfo
For Each fi In o.GetType().GetFields()
If fi.FieldType.Namespace = "google" Then
Dim hc As HtmlGenericControl = New
HtmlGenericControl("ul")
Dim li As HtmlGenericControl
Dim lc As LiteralControl
Dim content As String = String.Empty
subr =
CType(o.GetType().GetField(fi.Name).GetValue(o), Object())
Dim k As Integer
Select Case fi.FieldType.Name
Case "ResultElement[]"
For k = 0 To subr.Length - 1
subo =
Activator.CreateInstance(myGoogle.ResultElementType)
subo =
Convert.ChangeType(subr(k), myGoogle.ResultElementType)
Dim subfi As FieldInfo
For Each subfi In
Sandini Bib
Webservices konsumieren 1073
subo.GetType().GetFields()
content =
subo.GetType().GetField(subfi.Name).GetValue(subo).ToString()
li = New
HtmlGenericControl("li")
lc = New
LiteralControl(subfi.Name + ":
" + content)
li.Controls.Add(lc)
hc.Controls.Add(li)
Next
li = New
HtmlGenericControl("li")
lc = New
LiteralControl("<hr>")
li.Controls.Add(lc)
hc.Controls.Add(li)
Next
Case "DirectoryCategory[]"
For k = 0 To subr.Length - 1
subo =
Activator.CreateInstance(myGoogle.DirectoryCategoryType)
subo =
Convert.ChangeType(subr(k), myGoogle.DirectoryCategoryType)
Dim subfi As FieldInfo
For Each subfi In
subo.GetType().GetFields()
content =
subo.GetType().GetField(subfi.Name).GetValue(subo).ToString()
li = New
HtmlGenericControl("li")
lc = New
LiteralControl(subfi.Name + ":
" + content)
li.Controls.Add(lc)
hc.Controls.Add(li)
Next
li = New
HtmlGenericControl("li")
lc = New
LiteralControl("<hr>")
li.Controls.Add(lc)
hc.Controls.Add(li)
Next
End Select
t.Rows.Add(GetNewRow(fi.Name, hc))
Else
r =
o.GetType().GetField(fi.Name).GetValue(o)
Sandini Bib
1074 13 Webservices
t.Rows.Add(GetNewRow(fi.Name, New
LiteralControl(r.ToString())))
End If
Next
GoogleResultStream.Controls.Add(t)
End If
End Select
End Sub
gWsdl.PortTypes(0).Operations
GoogleServices.DataTextField = "Name"
GoogleServices.DataBind()
End If
End Sub
End Class
Listing 13.7: Das Programm WsdlChecker.aspx.vb – ein automatischer Webservice
E Sie handeln mit Waren aller Art? Dann bieten Sie Lieferanten
an, deren Daten per Webservice zu aktualisieren. Oder suchen
Sie Wiederverk.ufer, die ihre Server ber den Webservice mit
aktuellen Artikeldaten versorgen – und verkaufen Sie die Pro-
grammierung gleich mit ;-).
E Sie produzieren News, Rezensionen oder .hnliche immateriel-
le Dinge. Die Welt wartet darauf und mit einem Webservice ist
eine komfortable Cbernahme auf andere Server m(glich. Ist
Inhalt und Angebot reizvoll, kann man damit den einen oder
anderen Euro verdienen.
Imports System.IO
Imports System.Collections
Imports System.Diagnostics
Sandini Bib
Webservices anbieten 1079
Imports System.ComponentModel
Imports System.Web.Services
<WebService(Name:="Dateiaktualisierungdienst", _
Namespace:="http://www.joergkrause.de")> _
Public Class ServiceVariables
Inherits System.Web.Services.WebService
Public Sub New()
'CODEGEN: Dieser Aufruf ist fIr den
ASP.NET-Webdienst-Designer erforderlich.
InitializeComponent()
End Sub
Sie k:nnen den gesamten Dienst konfigurieren, indem Sie vor der Klas-
sendefinition das Attribut <WebService> einf5gen.
Sandini Bib
1080 13 Webservices
Sie finden oben den Namen der Methode wieder. Es ist nahe
liegend, dass hier mehrere Methoden aufgefhrt werden k(nnen.
W.hlen Sie nun die vorhandene Methode aus (siehe Abbildung
13.12).
Mit Klick auf (Aufrufen) wird nun der eigentliche Dienst gestartet
und die Antwort wird angezeigt (siehe Abbildung 13.14).
Wenn Sie sich nun wundern, warum Sie hier XML sehen: Webser-
vices dienen der Kommunikation zwischen Servern, nicht zwi-
schen Server und Mensch. Deshalb ist das Ausgabeformat XML.
Sandini Bib
Webservices anbieten 1081
<WebService(Namespace:="http://www.joergkrause.de")>
Parameter Bedeutung
Description Eine allgemeine Beschreibung
Name Der gew6nschte =ffentliche Name
Namespace Der Namensraum; ohne Angabe wird »tempuri.org«
verwendet
Tabelle 13.4: Parameter des Attributes <WebService> – alle vom Typ String
Sandini Bib
Webservices anbieten 1083
D Anhang
Sandini Bib
Sandini Bib
Seine Arbeitsschwerpunkte:
http://www.dotnet.comzept.de
Auf dieser Seite sind auch alle L:sungen zu den Jbungsaufgaben zu fin-
den. Sie k:nnen dort auch eigene L:sungen ver:ffentlichen und mit an-
deren Lesern diskutieren.
http://www.asp.net
Die Autoren selbst k(nnen Sie auf ihrer Homepage n.her kennen
lernen: http://www.buenning-krause.de
Sandini Bib
Informationen @ber professionelle Unterst@tzung 1089
Stichwortverzeichnis
! AddMinutes (Methode) 288 Arrays
<Serializable> (Attribut) 785 AddMonth (Methode) 288 BinarySearch 218
.NET 59 AddRange (ArrayList, BinarySearch (Array,
Host 68 Methode) 227, 230 Methode) 218
.NET Framework AddressOf 180-181 Compare (Methode) 220
installieren 40 AddSeconds (Methode) 288 Copy 218
Redistributable 40 AddStyleAttribute (Methode, CopyTo 218
.NET Framework SDK 40-41 HtmlTextWriter) 736 CreateInstance 218
.NET-Vision 59 AddYears (Methode) 288 GetEnumerator 218
@@IDENTITY (T-SQL) 428 ADO.NET 871 GetLength 218
@@ROWCOUNT (T-SQL) 428 Beziehungen 874 GetLength (Array,
@Control 961 Einschr:nkungen 874 Eigenschaft) 218
AutoEventWireUp 962 Aliase (SQL) 372 GetValue 218
@Control (Direktive) 655 AllKeys (Cookie, Length 218
@Import 959 Eigenschaft) 801 Rank 218
@OutputCache 960 ALTER DATABASE Reverse 219
@OutputCache (T-SQL) 383 SetValue 218
(Direktive) 811 ALTER PROCEDURE SetValue (Array, Methode)
@Page 955 (T-SQL) 436 218
AutoEventWireUp 956 ALTER TABLE (T-SQL) 388 Sort 219
Fehlersuche 956 ALTER VIEW (T-SQL) 425 Sortieren 220
@Reference (Direktive) 778 Alternativzweig (Select Verarbeiten 217
@Register 959 Case) 169 As 144
@Register (Direktive) 649 And 166 AS (SQL) 368
@Webservice (Direktive) 1077 AndAlso 166 ASCII 263
Anforderungen ascx-Datei 648
A weiterleiten 767 asiatische Schriftzeichen 296
Abandon (Methode) 784 Anzeige der Werte von ASP 3.0 29
Abandon (Session, Variablen 137 ASP-Einschr:nkungen 32
Methode) 788 Anzeigestatus 598 ASP.NET
Abfragen (SQL) 367 Append (StringBuilder, Sicherheits-
Abfragesprache in Methode) 266 funktionen 975
RowFilter 900 AppendFormat (StringBuilder, Verarbeitung 69
Abs (Math, Methode) 251 Methode) 266 Vorbereitung 35
abstrakt 201 Application (Klasse, ASP.NET-Abarbeitung 151
Accept-Language 297 Objekt) 807 ASPNET
Accept-Languages-Feld 299 Application (Objekt) 805 (Sicherheitskonto) 975
Access (Programm) 358 Application_Start aspnet_regiis.exe 42
SQL-Kommandos 361 (Ereignis) 809 aspnet_wp.exe siehe Worker
Achsenbezeichner Applikation 802 Process
(XPath) 472 Bedingte Ereignisse 805 Assemblies 68, 968
AcquireRequestState optimieren 821 AssemblyInfo.vb 742
(Ereignis) 803 Standardereignisse 802 Attributes (DirectoryInfo,
Add (ArrayList, Methode) 225 Variablen 805 Eigenschaft) 335
Add (Cookie, Methode) 800 Applikations- Attributes (FileInfo,
Add (Forms-Methode) 519, ereignismodell 802 Eigenschaft) 339
559 Applikationsmanagement 802 Attributes (Forms-Kollektion,
Add (Hashtable, Applikationsvariablen 805 Eigenschaft) 509
Methode) 228 =ra nach Christus 306 AusdrAcke 166
Add (Methode, Session) 784 ArgumentException Ausgabepufferung 752
Add (Methode, (Ausnahme) 341 Ausgabeverhalten eines
Zeitberechnung) 289 ArgumentNullException Steuerelements 723
AddAttribute (Methode, (Ausnahme) 341 Authenticate (Methode, Forms-
HtmlTextWriter) 724 ArrayList (Klasse) 225 Authentication) 983
AddDays (Methode) 288 AuthenticateRequest
AddHandler 180-181 (Ereignis) 803
Sandini Bib
1092 Stichwortverzeichnis
www.InformIT.de
InformIT.de, Partner von Addison-Wesley, ist unsere Antwort auf alle Fragen
der IT-Branche.
Copyright
Daten, Texte, Design und Grafiken dieses eBooks, sowie die eventuell angebotenen
eBook-Zusatzdaten sind urheberrechtlich geschützt. Dieses eBook stellen wir
lediglich als persönliche Einzelplatz-Lizenz zur Verfügung!
Jede andere Verwendung dieses eBooks oder zugehöriger Materialien und
Informationen, einschliesslich
• der Reproduktion,
• der Weitergabe,
• des Weitervertriebs,
• der Platzierung im Internet,
in Intranets, in Extranets,
• der Veränderung,
• des Weiterverkaufs
• und der Veröffentlichung
bedarf der schriftlichen Genehmigung des Verlags.
Insbesondere ist die Entfernung oder Änderung des vom Verlag vergebenen
Passwortschutzes ausdrücklich untersagt!
Bei Fragen zu diesem Thema wenden Sie sich bitte an: [email protected]
Zusatzdaten
Möglicherweise liegt dem gedruckten Buch eine CD-ROM mit Zusatzdaten bei. Die
Zurverfügungstellung dieser Daten auf unseren Websites ist eine freiwillige Leistung
des Verlags. Der Rechtsweg ist ausgeschlossen.
Hinweis
Dieses und viele weitere eBooks können Sie rund um die Uhr
und legal auf unserer Website
http://www.informit.de
herunterladen