Stand 04-2006 Institut für Systemarchitektur Lehrstuhl Rechnernetze Praktikum Rechnernetze Komplex II – Programmierung verteilter Anwendungen Praktikumsversuch .NET - Webservices und .NET-Remoting im Vergleich – Praktikumsdokumentation -1- Stand 04-2006 1 Einleitung ...................................................................................................................... - 3 - 2 Grundlagen .NET ......................................................................................................... - 3 2.1 Common Language Runtime (CLR) .................................................................. - 4 - 2.1.1 Common Intermediate Language ................................................................... - 5 - 2.1.2 Common Type System ................................................................................... - 6 - 2.1.3 Assemblies ..................................................................................................... - 6 - 2.1.4 Laufzeit-Host und Anwendungsdomänen ...................................................... - 7 - 2.1.5 Ausführung von verwaltetem Code................................................................ - 8 - 2.2 Klassenbibliothek ................................................................................................. - 8 - 2.2.1 3 2.3 Auslieferungsformen von .NET .......................................................................... - 9 - 2.4 Windows Communication Foundation............................................................. - 10 - Webservices & .NET-Remoting ................................................................................ - 11 3.1 5 Webservices......................................................................................................... - 11 - 3.1.1 Standards ...................................................................................................... - 11 - 3.1.2 Umgebung .................................................................................................... - 11 - 3.1.3 Internet Information Server .......................................................................... - 11 - 3.1.4 virtuelle Verzeichnisse ................................................................................. - 12 - 3.1.5 Vorgehen bei der Erstellung eines Webservices .......................................... - 12 - 3.1.6 Beispiel Webservice ..................................................................................... - 13 - 3.2 4 Organisation der Klassenbibliothek ............................................................... - 8 - .NET Remoting ................................................................................................... - 14 - 3.2.1 Remoting-Architektur .................................................................................. - 14 - 3.2.2 Eigenschaften entfernter Objekte ................................................................. - 15 - 3.2.3 Nutzung eines entfernten Objektes .............................................................. - 15 - 3.2.4 Beispiel .NET-Remoting .............................................................................. - 16 - Der Versuch ................................................................................................................ - 19 4.1 Versuchsbeschreibung ....................................................................................... - 19 - 4.2 Sicherung der Versuchsergebnisse ................................................................... - 20 - Literatur ...................................................................................................................... - 21 - -2- Stand 04-2006 1 Einleitung "42 - Das ist die Antwort auf die ultimative Frage in Per Anhalter durch die Galaxis von Douglas Adams ... .Net - Das ist die Antwort auf die ultimative Frage, die sich Microsoft in den letzten Jahren gestellt hat." Mit dieser Aussage beginnt Ralf Westphal in [1] seine Darstellung der .NET-Technologie. Die Frage, die sich Microsoft (MS) seit Mitte der 90iger Jahre gestellt hat ist allerdings deutlich leichter formulierbar, als Douglas Frage "nach dem Leben, dem Universum und dem ganzen Rest". Sie lautet in etwa folgendermaßen: "Wie kann eine homogene, leistungs- und anpassungsfähige Middlewareplattform mit hohem Abstraktionsgrad und intuitiver Handhabung zur Erstellung von (verteilten) Anwendungen und Komponentensystemen geschaffen werden, die zudem konkurrenzfähig zu aktuellen Entwicklungen auf diesem Gebiet ist?". Wie von Seiten Microsofts auf die Frage grundlegend geantwortet wurde, wird in der Folge zunächst dargestellt. Dabei wird insbesondere auf zwei für verteilte Anwendungen relevante Teilbereiche der .NET-Technologie, Webservices und .NET Remoting, eingegangen. Bei der Bearbeitung des Versuches werden die dazu gemachten Ausführungen angewandt. 2 Grundlagen .NET Das Wesen von .NET ist überwiegend geprägt durch einen Kompromiss zwischen Interoperabilität mit früheren Entwicklungen von Microsoft, insbesondere COM+ und zwischen offenen Standards. Maßgeblicher Standard bildet dabei die Common Language Infrastructure (CLI), die auf sprach- und plattformunabhängige Anwendungsentwicklung abzielt. Mit dieser Öffnung hin zu anderen Technologien und firmenfremden Standards vollzog Microsoft einen deutlichen Strategiewechsel, der das eigentlich Innovative dieser Plattform auszeichnet. Die technologische Basis der .NET-Technologie bildet zum einen eine mächtige Laufzeitumgebung, die so genannte Common Language Runtime (CLR) und zum anderen eine umfangreiche Klassenbibliothek. Diese Struktur ist in Abbildung 1 dargestellt. .NET-Framework Programmiersprachen Klassenbibliothek Werkzeuge Laufzeitumgebung Betriebssystem Abbildung 1: Struktur der .NET-Plattform -3- Stand 04-2006 2.1 Common Language Runtime (CLR) Kurz gesagt stellt die CLR die Umgebung für die Ausführung von Programmen in Form einer virtuellen Maschine dar, die als Abstraktion von einer konkreten Maschine fungiert. Die CLR lässt sich prinzipiell in ihrer Funktionalität und dem Ablauf der Programmausführung mit der Java Virtual Machine (JVM) vergleichen, unterscheidet sich allerdings in zwei Punkten maßgeblich: striktere Definition des Verhaltens der abstrakten Maschine Während in der Spezifikation der JVM über zahlreiche Details wie z.B. der Form der Codeausführung, bei der es sich im Fall der JVM prinzipiell auch um eine Interpretation handeln kann, keine Angaben gemacht werden, schreibt Microsoft eine Umwandlung in nativen Code vor. Sprachunabhängigkeit Die JVM wurde ausschließlich für die Ausführung von Bytecode geschaffen, der aus Java-Code erzeugt wurde. Auch wenn Ansätze existieren, diese Abbildung aus anderen Sprachen auf Java Bytecode heraus zu ermöglichen, sind diese überwiegend als unsauber zu bewerten. Erzielt wird die Sprachunabhängigkeit bei .NET durch das Common Type System. Wie der zweite Punkt andeutet, ist ein entscheidendes Design-Kriterium von .NET die Unabhängigkeit dieser Schicht von einer Programmiersprache. So existieren neben den so genannten .NET-Sprachen wie C# oder Visual C++ Unterstützung für eine sehr breite Palette weiterer Sprachen, wie Smalltalk, Perl, Python oder Haskell. Die Sprachunabhängigkeit besagt nicht, dass beliebige Sprachen innerhalb der eigentlichen Laufzeitumgebung unterstützt werden, sondern dass für die jeweilige Sprache eine Abbildung auf die Common Intermediate Language (CIL) vorliegt, sprich ein Programm dieser Sprache mittels eines Compilers in die CIL übersetzt werden kann. Dieser Zwischencode wiederum wird entweder zur Laufzeit (Just in Time) von der CLR in nativen Code übersetzt und ausgeführt oder aber im Vorfeld durch ein Programm (z.B: Ngen.exe) in nativen Code umgewandelt, der damit allerdings seine Plattformunabhängigkeit verliert. Als Ausführungsumgebung verwaltet die CLR auszuführenden Code, stellt Anwendungen Basisdienste bereit und erfüllt damit hauptsächlich folgende Aufgaben: Speicherverwaltung bzw. Heap-Verwaltung samt Freigabe nicht mehr benötigter Speicherbereiche (Garbage Collection – siehe dazu [5]) Verwaltung des Zugriffs auf die Klassenbibliothek Betriebssystemfunktionalitäten (inklusive Threadverwaltung) Bereitstellung einer sicheren Ablaufumgebung (auch für nicht vertrauenswürdigen Code) Unterstützung der Interoperabilität zwischen allen verfügbaren Sprachen Durchführung der Just-In-Time-Compilierung von Common Intermediate LanguageCode (s.u.) Laden von Programmen samt Auffinden aller Programmkomponenten und auf Die Struktur der CLR mit ihren wichtigsten Teilbereichen während der Abarbeitung einer Programmkomponente (Assembly) ist in Abbildung 2 dargestellt. -4- Stand 04-2006 CLR Anwendungsdomäne Programmlader Stack Assembly Klasse A Heap Klasse B JIT-Compiler Garbage-Collector Metadaten Laufzeit-Host Abbildung 2: Überblick über die CLR (in Anlehnung an [2], S. 126) 2.1.1 Common Intermediate Language Die CIL (früher Microsoft Intermediate Language – MSIL) orientiert sich in ihrem Aussehen stark an einem abstrakten nativen Befehlssatz eines Prozessors. Ihr liegt eine virtuelle StackMaschine mit entsprechend zahlreichen Stack-Operationen zugrunde. Wie bereits erwähnt handelt es sich bei einem Programm in CIL allerdings nicht um lauffähigen Code, sondern dieser wird grundsätzlich in den Code der real zugrundeliegenden Maschine übersetzt. Die Übersetzung erfolgt nicht für eine komplette Anwendung, sondern nur für die Teile bzw. einzelne Methoden der Anwendung, die tatsächlich benötigt werden, was zu einer Effizienzsteigerung und kürzeren Start-Up-Verzögerung führt. Der Vorteil einer Zwischensprache, wie es die CIL ist liegt neben Plattformunabhängigkeit und Abstraktion von einer tatsächlichen Maschine in Möglichkeit, Code vor der Ausführung auf Zuverlässigkeit und Sicherheit, insbesondere Typsicherheit zu überprüfen. Zudem wird somit eine spezifische Codeoptimierung für .NET-Technologie ermöglicht. der der auf die Es besteht ein sehr starker Zusammenhang zwischen der CIL und dem zugrunde liegenden Typsystem, was sich in einer engen Verknüpfung des Befehlssatzes mit dem CTS widerspiegelt. So wird beispielsweise das so genannte Boxing und Unboxing, also die Umwandlung eines gewöhnlichen Werttypen (int, short, ...) in ein Objekt und umgekehrt von der Zwischensprache unmittelbar unterstützt. Programme in CIL-Code werden auch als verwalteter (managed) Code bezeichnet. Abgrenzend dazu wird Code, der außerhalb der CLR ausgeführt wird als unmanaged bezeichnet. Abbildung 3 verdeutlicht den Weg von Quellcode unterschiedlicher Programmiersprachen zum ausführbaren Maschinencode. -5- Stand 04-2006 C#-Code C# C++ VB … C#- C++- VB …- Compiler Compiler Compiler Compiler if (a > b) max = a; else max = b; CIL-Code CIL-Code (+ Metadaten) IL_0004: ldloc.0 IL_0005: ldloc.1 IL_0006: ble.s IL_000c IL_0008: ldloc.0 IL_0009: stloc.2 IL_000a: br.s IL_000e IL_000c: ldloc.1 IL_000d: stloc.2 Maschinencode Lader mov ebx,-4[ebp] mov edx,-8[ebp] cmp ebx,edx jle 17 mov ebx,-4[ebp] mov -12[ebp],ebx ... Verifizierer JIT-Compiler Maschinencode Abbildung 3: Generierung von CIL- und Maschinencode (aus [3], S. 5) 2.1.2 Common Type System Massgebliches Problem bei der Herstellung von Interoperabilität zwischen Programmiersprachen bilden unterschiedliche Typsysteme, also die Festlegung, welche einfachen (ganze Zahlen, Wahrheitswerte etc.) bzw. welche komplexen Typen (Strukturen, Klassen etc.) existieren und wie diese repräsentiert werden. Somit liegt es nahe, einen kleinsten gemeinsamen Nenner bezüglich der zu unterstützenden Typen für die Programmiersprachen zu definieren. Genau diesen Weg ist .NET gegangen. Dabei wird innerhalb eines Regelwerkes, der Common Language Specification (CLS) genau festgelegt, wie die Abbildung der Sprachkonstrukte einer unterstützen Sprache auf die CIL erfolgt. Damit ist Interoperabilität sowohl zur Compilezeit, als auch zur Entwicklungszeit gewährleistet, es können also beispielsweise Klassen, die in einer Programmiersprache A geschrieben wurden von Klassen, die in einer Programmiersprache B geschrieben wurden abgeleitet oder Objekte von Klassen in anderen Programmiersprachen instanziiert werden. Grundlegend wird zwischen Werttypen und Referentypen unterschieden. Werttypen werden beim Programmablauf auf den Stack gelegt, während für Referenztypen ein spezieller Speicherbereich, der Heap verwendet wird. 2.1.3 Assemblies Großer Wert wurde bei der Handhabung von Programmierbausteinen auf komponentenorientierte Softwareentwicklung gelegt. Diese kleinsten Programmbestandteile werden als Assemblies (*.exe oder *.dll) bezeichnet und haben die Eigenschaft, selbstbeschreibend zu sein. Eine Assembly besteht potentiell aus mehreren Dateien, die CIL-6- Stand 04-2006 Code beinhalten. Zudem können Ressourcendateien wie Grafiken und dergleichen einer Assembly hinzugefügt werden. Die Beschreibung der eigenen Schnittstellen, Versionsangaben und benötigten Ressourcen erfolgen in Metadaten, die als Manifest bezeichnet werden und dem eigentlichen Programmcode beiliegen. Bei der Auslieferung und Installation von Software in Form von Assemblies müssen demnach nicht mehr aufwendige Registrierungen der Schnittstellen in der Windows-Registry erfolgen. Damit werden die Inbetriebnahme von Software und die Nutzung von Komponenten deutlich erleichtert. Assemblies sind wiederum unterteilt in Module. Eine Assembly besteht aus mindestens einem Modul. Der übersetzte CIL-Code wird innerhalb dieser Module abgelegt und durch eigene Metadaten beschrieben. Eine Aufteilung einer Anwendung in einzelne Module ist in heutigen Entwicklungsprozessen durchaus wünschenswert, zumal Module in unterschiedlichen Sprachen geschrieben sein können. Ein weiterer Vorteil dieses Konzepts bildet die Tatsache, dass eine Anwendung modulweise in den Speicher geladen wird. Speicher wird also erst dann von einem Modul belegt, wenn dieses auch tatsächlich benötigt wird. Allerdings ist ein Modul mangels Manifest nicht eigenständig ladbar, sondern nur falls eine Assembly Code aus diesem Modul aufruft. Aus einer C#-Quellcodedatei kann durch den Aufruf „csc /target:module Dateiname.cs“ ein Modul erzeugt werden. Abbildung 4 zeigt eine dll-Datei, bestehend aus mehreren Modulen und dem Manifest. Die Assembly-Datei A.dll umfasst damit die drei Module A, B und C. A.dll B.netmodule C.netmodule Modul A Modul B Modul C Manifest Abbildung 4: Assembly bestehend aus mehreren Modulen Durch eine nicht zentrale Speicherung aller notwendigen Informationen, insbesondere Versionsinformationen zu einer Komponente ist ein Ausweg aus der so genannten "DLLHölle", die den Konflikt zwischen unterschiedlichen Versionen einer Komponente auf einem Rechner beschreibt, geschaffen worden. 2.1.4 Laufzeit-Host und Anwendungsdomänen Die CLR ist zunächst keine eigenständige Applikation, sondern wird für gewöhnlich innerhalb einer anderen Anwendung ausgeführt, die als Laufzeit-Host bezeichnet wird. Diese sorgt für die Initialisierung und das Laden der CLR. Das reguläre .NET-Framework bringt bei seiner Auslieferung die drei Laufzeit-Hosts ASP.NET, Microsoft Internet Explorer und ausführbare Shelldateien mit und unterstützt durch zahlreiche APIs die Erstellung eigener Laufzeit-Hosts. -7- Stand 04-2006 Wie in Abbildung 2 dargestellt, läuft eine Assembly innerhalb einer so genannten Anwendungsdomäne ab. Der umgebende Prozess wird damit in weitere logische Einheiten zerteilt. Durch sie wird zudem der Heap, auf dem alle Verweistypen (Klassentypen, …) gespeichert werden, gekapselt. Die mit diesem Konzept erzielte Separation einzelner Assemblies während der Ausführung macht Anwendungsdomänen mit Prozessen des Betriebssystems vergleichbar. Die Einteilung in Anwendungsdomänen hat zwei grundlegende Vorteile: 1. Anwendungsdomänen bilden effizientere Einheiten, als grobgranulare Prozesse. 2. Durch Anwendungsdomänen wird ein prozessähnliches Konstrukt geschaffen, das vom zugrunde liegenden Prozessmodell und damit vom verwendeten Betriebssystem abstrahiert, was dem Anspruch von .NET, plattformunabhängig zu sein, gerecht wird. 2.1.5 Ausführung von verwaltetem Code Bei der Ausführung von verwaltetem Code tritt zunächst der Programm-Loader in Erscheinung. Er sucht nach der benötigten Assembly und lädt sie in den Speicher. Dieser Vorgang ist äußerst komplex und soll hier nur kurz angeschnitten werden. Zunächst prüft der Loader, ob die Assembly bereits geladen wurde. Ist dies nicht der Fall durchsucht er den so genannten Global Assembly Cache (GAC), ein Verzeichnis, in dem sich standardmäßig Assemblies befinden, die global, durch mehrere Programme genutzt werden können. Ist die Suche auch hier erfolglos werden spezielle Konfigurationsdateien der aufrufenden Anwendung durchsucht, die Auskunft über den Ort geben können. Bei erneuter Erfolglosigkeit wird die Suche in dem so genannte Stammverzeichnis fortgesetzt, bei dem es sich entweder um das Verzeichnis handelt, in dem die Anwendung liegt oder aber um einen entfernten Pfad zu einem anderen Rechner. Dieser Schritt unterstreicht die Netzwerkzentrierung der .NET-Technologie. Eine gewöhnliche Anwendung kann also vollkommen transparent Assemblies auf entfernten Rechnern nutzen. Nachdem die Assembly gefunden und geladen wurde, werden ihre in CIL vorliegenden Methoden nach und nach bei Bedarf in nativen Code übersetzt und ausgeführt. 2.2 Klassenbibliothek Neben der CLR ist eine umfangreiche, objektorientierte Klassenbibliothek das zweite Standbein der .NET-Technologie. Sie umfasst mehrere tausend Klassen und Datentypen und stellt eine Vielzahl vorgefertigter Frameworks für Netzwerkkommunikation, Datenbankzugriffe (ADO.NET) etc. zur Verfügung. Weiter unten wird beispielsweise genauer auf das .NET-Remoting-Framework eingegangen. 2.2.1 Organisation der Klassenbibliothek Die Klassenbibliothek ist hierarchisch in baumartigen Strukturen organisiert. Die jeweiligen Knoten und Blätter werden als Namensräume (namespace) bezeichnet. Ausgangspunkt bilden die beiden Wurzelelemente System und Mircosoft. Die vom Namensraum System abgeleiteten Namensräume bieten Funktionalitäten an, die unabhängig von der Ausführungsumgebung, insbesondere unabhängig von einer Microsoft-Plattform sind und so auch in anderen zugrunde liegenden Systemen verwendet werden können. Bei den vom Namensraum Microsoft abgeleiteten Namensräumen handelt es sich analog um an eine Microsoft-8- Stand 04-2006 Umgebung gebundene Klassen. Ein kleiner Ausschnitt der Namensraumhierarchie ist in Abbildung 5 dargestellt. Für den Praktikumsversuch wird u.a. der Namensraum System.Web.Services relevant sein. System … System.Collections Microsoft … System.Data … System.Web … Microsoft.CSharp Microsoft.Win32 … … System.Web.Services Abbildung 5: Ausschnitt aus der Namensraumhierarchie von .NET Ähnlich zu Java ist die Wurzel jeder Ableitungsfolge die Klasse System.Object, die grundlegende Funktionalitäten anbietet, wie die Methoden Equals() oder ToString(). Auch reguläre Werttypen sind mit dem Typ System.Object kompatibel, können also objectVariablen zugewiesen werden. 2.3 Auslieferungsformen von .NET Microsoft bietet eine breite Palette von Formen an, wie und mit welchen Werkzeugen etc. .NET ausgeliefert wird. Geht es nur darum, .NET-Programme ausführen zu können, so kann eine isolierte Laufzeitumgebung gemeinsam mit der Klassenbibliothek kostenlos von den Internetseiten von Microsoft herunter geladen werden. Daneben existiert das ebenso kostenlose Software Development Kit (SDK), das zusätzlich zur Laufzeitumgebung und Klassenbibliothek zahlreiche Werkzeuge, wie Compiler, Disassembler, Debugger und ähnliches mitbringt. Als kostenpflichtige Formen werden darüber hinaus eine umfangreiche Entwicklungsumgebung (Visual Studio .NET) angeboten. In neusten Server-Plattformen aus der Microsoft Windows Reihe ist .NET bereits integraler Bestandteil. Für Kleinstgeräte wie Mobiltelefone, auf denen zugeschnittene Windows-Versionen laufen, stellt Microsoft eine an die eingeschränkten Ressourcen der Geräte angepasste .NETLaufzeitumgebung, namentlich das .NET Compact Framework zur Verfügung. Aufgrund der Offenheit des .NET-Frameworks existieren auch erste Ansätze von anderen Anbietern und freien Entwicklergemeinschaften, eine eigene Version der Entwicklungs- und Laufzeitumgebung zu erstellen. Bekannt ist dabei das Open-Source-Projekt Mono, das auf zahlreichen Betriebssystemen (u.a. Linux, BSD-Derivate, …) lauffähig ist. -9- Stand 04-2006 2.4 Windows Communication Foundation .NET ist keine abgeschlossene Technologie, sondern unterliegt einer starken Dynamik, da Microsoft große Entwicklungsanstrengungen aufbringt, um es weiterzuentwickeln und in unterschiedlichste Bereiche zu integrieren. Eine momentane Entwicklungsrichtung, die als Windows Communication Foundation (WCF) oder auch als Indigo bezeichnet wird, zielt dabei auf die Entwicklung einer einheitlichen, standardisierten Kommunikationsinfrastruktur für verteilte Anwendungen ab, die den Grundgedanken von Webservices weiterführt und auf andere Kommunikationsmodelle umsetzt. Dieses System basiert dabei auf dem .NETFramework und führt einige Erweiterungen ein. Geplant ist eine Veröffentlichung mit Microsoft Windows Vista, aber ebenso die Unterstützung früherer Microsoft Windows Systeme. Für weitere Informationen zu dieser Thematik siehe [6]. - 10 - Stand 04-2006 3 Webservices & .NET-Remoting Nachdem fundamentale Begriffe und Konzepte der .NET-Technologie eingeführt wurden, werden nun die theoretischen und praktischen Vorkenntnisse für den Themenbereich des Praktikums behandelt und diese dann jeweils an einem kleinen Beispiel beleuchtet. Es handelt sich um zwei Möglichkeiten auf Basis der .NET-Technologie verteilte Anwendungen zu realisieren: Webservices und .NET-Remoting. Sie sind in ihrem Anwendungsgebiet und ihrer Zieletzung deutlich verschieden. Neben diesen beide Kommunikationsformen haben zwei weitere Technologien große Relevanz bei der Realisierung verteilter Anwendungen auf Grundlage von Windows. Dies sind das proprietäre DCOM, das eng mit COM verbunden ist und MS Message Queues, die zur Realisierung nachrichtenorientierter Anwendungen eingesetzt werden. 3.1 Webservices Die folgenden Ausführungen geben eine kurze Einleitung in die Thematik der Webservices innerhalb einer .NET-Umgebung. Auf die einzelnen Protokolle und Mechanismen wird an dieser Stelle nicht näher eingegangen. Sie erfahren neben einer allgemeinen Betrachtung des Industriestandards der "Webservices" Behandlung im Studienmaterial zu den Praktikumsversuchen. 3.1.1 Standards Das Feld der Webservices, die auf Grundlage von .NET erstellt und angeboten werden können, stützt sich auf die vier Standards XML, SOAP, WSDL und UDDI. Die .NET-Webservice-Schnittstelle versteht drei verschiedene Übertragungsprotokolle: 1. HTTP-GET (Parameterübergabe erfolgt über die URL) 2. HTTP-POST (Parameterübergabe erfolgt in einem separaten Datenstrom) 3. SOAP (Parameterübergabe erfolgt innerhalb dieses XML-Formats, das selbst wiederum per HTTP-POST zugestellt wird) Alle Kommunikationsvarianten stützen sich somit auf das HTTP-Protokoll, das in jedem gängigen System Unterstützung findet. 3.1.2 Umgebung Das Betriebssystem Microsoft Windows bringt in zahlreichen Versionen (Windows NT Server, Windows 2000 Server, Microsoft Windows Server 2003, Windows 2000 Professional, Windows XP Professional u.a.) alle Voraussetzungen mit, um Webservices anbieten zu können. Wichtig sind dazu zum einen das .NET-Framework 2.0 (in der Form des Software Development Kits), das kostenlos von den Seiten von Microsoft bezogen werden kann und zum anderen ein lauffähiger Internet Information Server (IIS). 3.1.3 Internet Information Server Beim IIS handelt es sich um eine Sammlung von Serverfunktionalitäten, die in das Betriebssystem Microsoft Windows integriert sind. Insbesondere bringt er alle - 11 - Stand 04-2006 Voraussetzungen für einen modernen Webserver mit und unterstützt so eine Vielzahl an unterschiedlichen Webtechnologien, wie etwa ASP.NET. Sollte der IIS auf einem der genannten Systeme nicht installiert sein, so kann dies über den Assistenten für Windows-Komponenten nachgeholt werden. Zur Installation findet er sich beispielsweise unter Windows XP Professional als Eintrag "Internet Informationsdienste" unter Start->Einstellungen->Systemsteuerung->Software->Windows-Komponenten hinzufügen/entfernen. Nach der Installation kann der IIS unter Windows XP Professional innerhalb der Systemsteuerung unter Verwaltung -> Internet-Informationsdienste konfiguriert und angepasst werden. 3.1.4 Virtuelle Verzeichnisse Die eigentliche Webservice-Applikation wird in einem virtuellen Verzeichnis abgelegt, das vom IIS verwaltet wird. Dazu muss zunächst ein solches Verzeichnis erstellt und mit einem physikalischen Verzeichnis verknüpft werden. Zum Erstellen eines virtuellen Verzeichnisses muss innerhalb der Konfigurationsumgebung des IIS die angezeigte Baumstruktur geöffnet werden, so dass der Menüpunkt "Standardwebsite" sichtbar wird. Nach einem Rechtsklick auf diesen Eintrag kann über "Neu" und der Befolgung der Dialogschritte ein virtuelles Verzeichnis mit einem lokalen Ordner verbunden werden. 3.1.5 Vorgehen bei der Erstellung eines Webservices Als erster Schritt muss eine Klasse implementiert werden, die Methoden als Webservices im Intra- oder Internet anbieten soll. Diese unterscheidet sich nur durch drei Zusätze von einer regulären Klasse. 1. Sie besitzt eine Direktive, die die Klasse zu einer Web-Service-Klasse macht: <%@ WebService Language="C#" class="ClassName"%> In dieser Direktiven wird zudem die verwendete Sprache, hier die .NET-Sprache C# angegeben. 2. Sie ist von der Klasse System.Web.Services.WebService abgeleitet (was z.B. durch das Attribut [WebService] erreicht wird). 3. Jede Methode, die als Webservice aufgerufen werden kann, ist mit dem Attribut [WebMethod] versehen. Die so erstellte Klasse wird in einer Datei mit der Endung .asmx abgespeichert, in einem virtuellen Verzeichnis abgelegt und kann daraufhin bereits mit einem Browser angesprochen werden. Um die gesamten Vorgänge der Schnittstellen-Publikation, der Kompilierung usw. kümmert sich die .NET-Umgebung vollkommen eigenständig. Die Schnittstelle wird in WSDL beschrieben. Aus dieser Beschreibung kann sich ein Client mit Hilfe des Programms „wsdl“ eine Proxy-Klasse generieren. Der Client selbst spricht dann den Proxy an, der sich um die Kommunikationsdetails mit dem Webservice, insbesondere um die Umwandlung zwischen Formaten der übergebenen Werte kümmert. - 12 - Stand 04-2006 3.1.6 Beispiel Webservice Die Erstellung eines Webservices wird in der Folge anhand eines kleinen Beispiels demonstriert. Bei dem Beispiel handelt es sich um einen Webservice, der zwei int-Werte miteinander multipliziert und das Ergebnis der Operation zurück liefert. Der gesamt Quellcode für diese Anwendung sieht folgendermaßen aus: // Multiplier.asmx <%@ WebService Language="C#" class="Multiplier" %> using System; using System.Web.Services; [WebService(Namespace="http://localhost/beispiel/")] class Multiplier { [WebMethod] public int multiplyValues(int x, int y) { return x * y; } } Diese Datei ist unter dem Namen Multiplier.asmx abzuspeichern und in einem virtuellen Verzeichnis abzulegen. Im Beispiel wurde die Datei im physikalischen Verzeichnis „C:\beispiel“ gespeichert, das auf das virtuelle Verzeichnis „beispiel“ abgebildet ist. Auf dem Praktikumsrechner kann das Verzeichnis C:/Inetpub/wwwroot/Versuch.Net/Benutzername verwendet werden. Bei lokal laufendem IIS ist der Webservice durch Eingabe der URL http://localhost/beispiel/Multiplier.asmx (bzw. auf dem Praktikumsrechner (141.76.40.92): http://localhost:8000/Versuch.Net/Benutzername/Multiplier.asmx) von einem Web-Browser aus erreichbar. Die IIS- bzw. .NET-Infrastruktur sorgt für die automatische Generierung einer HTML-Seite, über die sich der Webservice ansprechen lässt. Durch klicken auf den Link „multiplyValues“ auf dieser Seite kann die Methode getestet werden. Zudem befinden sich dort einige Informationen zum Aufrufmechanismus. Für alle Parameter der Methode wird ein Formularfeld bereitgestellt. Die Rückgabe des Tests wird in Form einer XML-Kodierung präsentiert, die im Falle der Eingabe von „2“ und „3“ als Parameter folgende Form hat: <?xml version="1.0" encoding="utf-8" ?> <int xmlns="http://localhost/beispiel/">6</int> Wie bereits erwähnt kümmert sich die zugrunde liegende Infrastruktur eigenständig um die Generierung einer WSDL-Beschreibung aus einer Webservice-Klasse. Diese kann durch Eingabe von „?WSDL“ hinter der URL des Webservices, im Beispiel also http://localhost/beispiel/Multiplier.asmx?WSDL betrachtet werden. Aus dieser Beschreibung wird von der Eingabeaufforderung aus durch den Aufruf wsdl /out:Multiplier.cs http://localhost/beispiel/Multiplier.asmx?WSDL eine Proxy-Klasse erzeugt, die in der Datei Multiplier.cs abgelegt wird. Diese steht somit beispielsweise einem ASP.NET- oder auch einem eigenständigen Client zur Verfügung und ermöglicht eine Nutzung des Webservices, als handele es sich um eine lokale Klasse. - 13 - Stand 04-2006 3.2 .NET Remoting Webservices stellen eine standardisierte und einfache Möglichkeit dar, auf entfernte Funktionalitäten zuzugreifen. Neben diesem Konzept zur Bereitstellung von Diensten über das Internet bietet .NET eine Lösung für Anwendungen aus verteilten bzw. entfernten Objekte an: .NET-Remoting. Diese Technologie gilt als eine leichtgewichtige und effiziente Form zur Publikation und Nutzung von Remote-Objekten. 3.2.1 Remoting-Architektur Die Grundlage der Kommunikation per .NET-Remoting bilden so genannte Kanäle (Channels) über die Daten zwischen Client und Server in einem bestimmten Protokollformat, in das sie mit Hilfe von Formatierern (Formattern) gebracht werden, übertragen werden. Als wichtigste Kanäle existiert zum einen der HTTP-Kanal, über den Daten im SOAP-Format geschickt werden und zum anderen der TCP-Kanal, der Daten in einem Binärformat übermittelt. Daneben gibt es zahlreiche weitere, insbesondere proprietäre Kanäle. Die so genannte Channel-Architektur samt Kommunikationsvorgang ist in Abbildung 6 dargestellt. Clientprozess Serverprozess int x = 12; Result = Obj.callRemote(x); ... entferntes Objekt 1 5 Proxy Formatter Dispatcher 2 Formatter 4 3 Transportkanal (z.B. binäre Kodierung oder SOAP-Format) Abbildung 6: Kommunikationsvorgang per .NET-Remoting Der Ablauf ist dabei folgendermaßen: 1. Ein Client-Prozess ruft eine Methode eines entfernten Objektes auf, der tatsächlich an ein lokales Proxy-Objekt weitergeleitet wird. 2. Mithilfe eines Formatters wird der Aufruf in eine übertragbare Form gebracht. - 14 - Stand 04-2006 3. Innerhalb des Remoting-Subsystems erfolgt die Übermittlung der Daten auf einem zuvor angeforderten Kanal. 4. Auf der Seite des entfernten Objekts wird der Aufruf entgegen genommen und zurück in das ursprüngliche Format transformiert. 5. Über einen Dispatcher, der zeitgleiche Zugriffe reguliert wird der Aufruf schließlich an das entfernt nutzbare Objekt weitergereicht. Der Weg von Rückgabedaten ist zum Aufruf analog. 3.2.2 Eigenschaften entfernter Objekte Um durch das .NET-Remoting-System nutzbar zu sein, müssen entfernte Objekte direkt oder indirekt von der Klasse MarshalByRefObjekt erben. Sie müssen eigenständig für die Reservierung eines Kanals an einen bestimmten Port sorgen und ihre remote nutzbare Funktionalität explizit registrieren. Wie dieses im Detail aussieht, wird im Beispiel weiter unten behandelt. Entfernte Objekte werden je nach Form ihrer Aktivierung und Verwaltung in zwei Kategorien eingeteilt. Bei Server Activated Objects (SAO) übernimmt die Server-Seite transparent für den Client die Instanziierung etc., während bei Client Activated Objects (CAO) ein entferntes Objekt explizit von und für einen Client instanziiert wird und maximal für die Dauer der Sitzung erhalten bleibt. Die Kategorie der SAO wird weiter eingeteilt in: SingleCall-Objekt Lebt nur für die Dauer eines Methodenaufrufs und ist somit für die Haltung eines internen Zustands nicht verwendbar. Singleton-Objekt Das Objekt wird exakt einmal instanziiert und bearbeitet Methodenaufrufe in parallelen Threads. Es eignet sich damit zur Speicherung eines internen Zustands, kann also Instanzvariablen besitzen. 3.2.3 Nutzung eines entfernten Objektes Der Client, der ein entferntes Objekt nutzen will muss über zwei Informationen verfügen: 1. Die Adresse des entfernten Objektes, die entweder fest in den Sourcecode einkompiliert oder aber in einer Konfigurationsdatei angegeben wird. 2. Die Beschreibung der benötigten Methode (Name, Parameter, Rückgabewert). Diese wird ihm in der Regel durch ein Interface der verwendeten Programmiersprache bekannt gegeben. Nachdem der Client einen Kommunikationskanal angefordert hat, kann er eine Referenz auf ein entferntes Objekt beantragen. Dazu kann die statische Methode GetObject() der Klasse Activator verwendet werden. Durch den damit angestoßenen Ablauf wird auf Client-Seite ein Proxy-Objekt erstellt, dem Client zugeordnet und an diesen Proxy eine Referenz auf das entfernte Objekt gebunden. Wird nun eine Methode des entfernten Objekts aufgerufen, verläuft die gesamte Kommunikation über das Proxy-Objekt, das die Serialisierung ausgehender und Deserialisierung eingehender Daten realisiert. - 15 - Stand 04-2006 3.2.4 Beispiel .NET-Remoting Ebenso wie im Falle des Webservices soll nun eine Beispielanwendung entwickelt werden, die auf Basis von .NET-Remoting die Multiplikation zweier int-Werte innerhalb eines entfernten Objektes ermöglicht. Dazu sind drei verschiedene Bestandteile zu erstellen: ein Server-Programm, das der Einfachheit halber direkt das entfernt nutzbare Objekt (SingleCall) beinhaltet ein Client-Programm, das eine Methode des Objekts nutzt eine Beschreibung der Schnittstelle der Methoden des entfernten Objektes, die in Form eines Interfaces dem Client zur Verfügung gestellt wird. Als Channel zwischen Client und Server wird ein TCP-Kanal verwendet. Demnach hat der Server folgenden Aufbau: //Multiplier.cs using System; using System.Runtime.Remoting; using System.Runtime.Remoting.Channels; using System.Runtime.Remoting.Channels.Tcp; namespace Multiplier{ public class Multiplier : MarshalByRefObject, IMultiplier.IMultiplier { public Multiplier() { } public int multiply(int x, int y){ return x*y; } public static void Main(){ TcpServerChannel channel = new TcpServerChannel(2342); ChannelServices.RegisterChannel(channel,false); WellKnownServiceTypeEntry remoteObject = new WellKnownServiceTypeEntry( typeof(Multiplier), "Multiplier", WellKnownObjectMode.SingleCall ); RemotingConfiguration.RegisterWellKnownServiceType(remoteObject); Console.WriteLine("Server is running..."); Console.ReadLine(); } } } - 16 - Stand 04-2006 Zunächst registriert der Server den gewünschten Kanal und daraufhin das entfernte Objekt vom Typ Multiplier als SingleCall-Objekt. Auffallend an diesem Code ist die fehlende Verbindung zwischen dem deklarierten Kanal und dem entfernten Objekt. Diese Beziehung wird intern vom .NET-Remoting-Framework hergestellt. Das vom Server implementierte Interface beinhaltet die Beschreibung der MethodenSchnittstelle und steht Client und Server zur Verfügung. Es hat folgenden Aufbau: //IMultiplier.cs using System; namespace IMultiplier { public interface IMultiplier { int multiply(int x, int y); } } Für den Client ergibt sich folgender Code: //MultiplierClient.cs using System; using System.Runtime.Remoting; using System.Runtime.Remoting.Channels; using System.Runtime.Remoting.Channels.Tcp; namespace MultiplierClient{ class MultiplierClient{ [STAThread] static void Main(string[] args) { TcpClientChannel channel = new TcpClientChannel(); ChannelServices.RegisterChannel(channel,false); IMultiplier.IMultiplier multiplier = (IMultiplier.IMultiplier)Activator.GetObject ( typeof(IMultiplier.IMultiplier), "tcp://localhost:2342/Multiplier" ); int result = multiplier.multiply(2, 3); Console.Write(result); } } } - 17 - Stand 04-2006 Analog zum Server erfolgt zunächst die Registrierung des Channels und daraufhin die Anforderung einer Referenz auf das entfernten Objekt. Die einfachste Möglichkeit dazu ist die Nutzung der Methode Activator.GetObject(). Das zurück gegebene Proxy-Objekt kann nach einem Cast auf den gewünschten Typ (hier im Format Namespace.Interface) wie ein lokales Objekt verwendet werden. Damit der Client die aufzurufende Schnittstelle kennt, wird ihm diese bei der Kompilierung mitgeteilt: csc MultiplierClient.cs IMultiplier.cs //Übersetzung Client csc Multiplier.cs IMultiplier.cs //Übersetzung Server Die beiden erzeugten *.exe-Dateien können daraufhin gestartet werden. Neben der unmittelbaren Festlegung der Verbindungs- (Adresse/Port des entfernten Objekts etc.) oder der Channelparameter im Quellcode können diese Daten Client bzw. Server ebenso per XML-Konfigurationsdatei bekannt gegeben werden, was den Vorteil der einfachen Konfigurierbarkeit mit sich bringt. Im Falle des obigen Clients sieht eine solche Konfigurationsdatei wie folgt aus: <configuration> <appSettings> <add key="reference" value="http://localhost:2342/entferntesObjekt" /> </appSettings> <system.runtime.remoting> <application> <channels> <channel ref="http"/> </channels> </application> </system.runtime.remoting> </configuration> Diese wird standardmäßig nach dem Schema Assemblyname.Assemblytyp.config im Verzeichnis der Assembly gespeichert, im Beispiel also unter MultiplierClient.exe.config. Daraufhin kann sie über das nachfolgende Codesegment geladen und auf ihrer Basis eine Referenz auf ein entferntes Objekt angefordert werden. String configfilename = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile; RemotingConfiguration.Configure(configfilename,false); IMultiplier.IMultiplier multiplier = (IMultiplier.IMultiplier)Activator.GetObject ( typeof(IMultiplier.IMultiplier), System.Configuration.ConfigurationManager.AppSettings["reference"] ); - 18 - Stand 04-2006 4 Der Versuch Bei der Anwendung handelt es sich um ein verteiltes Flugbuchungssystem, das Funktionalitäten sowohl auf Basis von Webservices, als auch auf Basis von .NET-Remoting zur Verfügung stellt. Mit Hilfe eines Client-Programms ist es möglich, die bereitgestellten entfernten Methoden zu nutzen und so Flüge zu buchen, Buchungen anzuzeigen und neue Flugverbindungen einzutragen. Voraussetzung für die Bearbeitung des Versuchs ist ein installiertes, aktuelles .NETFramework (der Versuch wurde auf Basis der Framework-Version 2.0 erstellt). Dieses kann von den Internet-Seiten von Microsoft bezogen werden. Daneben muss auf dem verwendeten Rechner der IIS laufen. Eine Programmierumgebung wie etwa Visual Studio ist nicht erforderlich. Alle Dateien können und sollten mit einem Texteditor bearbeitet werden. Das System ist in C# geschrieben. 4.1 Versuchsbeschreibung Nach dem Download der Sourcen von den Seiten des Lehrstuhls und dem Entpacken des Archivs liegen die Programmkomponenten in den Unterordnern „client“, „server“ und „data“ vor. Im Ordner „data“ befinden sich die beiden Dateien DataBase.xml und DataDescription.xsd, die zum einen die Datenbasis und zum anderen die Beschreibung des Datenmodells in Form von XML-Dateien bilden. Der Datenzugriff von Seiten des Servers wird durch die Klasse DataManager in der Datei DataManager.cs durchgeführt. Der Versuch kann auf dem Praktikumsrechner (141.76.40.92) des Lehrstuhls Rechnernetze bearbeitet werden. Dazu wurde unter C:/Inetpub/wwwroot/Versuch.Net/ für jeden Benutzer ein Verzeichnis mit der Bezeichnung des Benutzernamens angelegt. Wird das Archiv unmittelbar in dieses Benutzerverzeichnis entpackt, so kann der Webservice über die URL http://localhost:8000/Versuch.Net/Benutzername/server/FlightManager.asmx angesprochen werden. Damit der Webservice bzw. der Remoting-Server auf die Datenbasis zugreifen kann, müssen die Rechte für die Datei DataBase.xml entsprechend angepasst werden. Der Einfachheit halber kann der Benutzergruppe „Authenticated Users“ voller Zugriff gewährt werden. Folgende Dateien sind für die Bearbeitung des Versuchs relevant: Datei Aufgabe Server/FlightManager.asmx Stellt Funktionalitäten als Webservices zur Verfügung und greift dazu auf die Datenbasis zu. Ermöglicht das Hinzufügen einer Flugverbindung zum Datenbestand mittels .NET-Remoting. Server/FlightAdd.cs Client/FlightClient.cs Bildet die Hauptklasse des Clients, in der fundamentale Initialisierungen vorgenommen werden. Client/FlightClient.exe.config Beinhaltet XML-Konfigurationsdaten für die Kommunikation per .NET-Remoting Client/IFlightAdd.cs Die Interface-Beschreibung des per .NET-Remoting Server/IFlightAdd.cs nutzbaren entfernten Objekts - 19 - Stand 04-2006 Die folgenden Aufgaben sind durchzuführen: I. II. III. IV. V. VI. VII. Die Datei Server/FlightManager.asmx ist so zu erweitern, dass die Methoden getAirports(), getFlights(), getFlightData(), storeBooking(), getBookings(), getBookingData() und deleteBookingData() als Webservice-Methoden ansprechbar sind. Zudem ist der Pfad zu den Dateien DataBase.xml und DataDescription.xsd bei der Instanziierung der Klasse DataManager anzugeben. Aus der WSDL-Beschreibung des Webservices ist eine Proxy-Klasse für den Client zu erstellen. Diese muss unter dem Namen FlightManager.cs im ClientVerzeichnis abgelegt werden. In der Datei Server/FlightAdd.cs sind in der Main-Methode die notwendigen Ergänzungen für die Initialisierung eines TCP-Channels (Port 4223) und der Nutzbarmachung der Klasse FlightAdd als entferntes Objekt unter dem Namen „FlightAdd“ in Form des SingleCall-Objektes (SOA) mit der Methode addFlight() durchzuführen. Auch hier ist der Pfad der Dateien DataBase.xml und DataDescription.xsd bei der Instanziierung der Klasse DataManager anzugeben. Die beiden Dateien IFlightAdd.cs sind mit der Angabe des Interfaces für das entfernte Objekt bzw. dessen Methoden zu vervollständigen (für Client und Server). Die Konfigurationsdatei Client/FlightClient.exe.config ist so zu erweitern, dass auf ihrer Basis das entfernte Objekt per Remoting genutzt werden kann. Im Konstruktor der Klasse FlightClient sind entsprechende Ergänzungen zum Laden der Konfigurationsdatei FlightClient.exe.config zu machen. Dabei wird die Referenz auf das entfernte Objekt der Variablen „adder“ zugewiesen. Vergleichen Sie kurz die beiden Technologien .NET-Webservices und .NETRemoting in Bezug auf Standardisierung und bevorzugter Einsatzzweck und führen Sie die maßgeblichen Vor- und Nachteile auf. Die Antworten sind in der Datei „Aufgabe7.txt“ abzulegen. Nach erfolgreicher Abarbeitung der Punkte 1-6 kann das Client- und Serverprogramm jeweils von der Kommandozeile aus übersetzt und gestartet werden. Die Übersetzung geschieht beispielsweise durch die folgenden beiden Aufrufe: csc FlightClient.cs AddFlights.cs BookFlight.cs ShowFlights.cs IFlightAdd.cs FlightManager.cs //Übersetzung Client csc FlightAdd.cs DataManager.cs IFlightAdd.cs //Übersetzung Server 4.2 Sicherung der Versuchsergebnisse Nachdem die richtige Funktionsweise der Versuchsergebnisse ausreichend getestet wurde, sind folgende Dinge zu tun: 1. Anlegen des Ordners „Lösungen.NET“ im Unterverzeichnis „Lösungen“ des eigenen Verzeichnisses auf dem Praktikumsrechner 2. Speicherung der veränderten und erstellten Dateien (FlightManager.asmx, FlightManager.cs, FlightClient.cs, FlightClient.exe.config, FlightAdd.cs, IFlightAdd.cs, Aufgabe7.txt) in diesem Verzeichnis 3. Mail mit dem Betreff „Versuch .NET“ an [email protected] unter Angabe des Namens, Vornamens, der Matrikelnummer und des Logins verschicken 4. Kopie der Versuchsergebnisse bis zur Ausgabe der Scheine sichern - 20 - Stand 04-2006 5 Literatur [1] Einführung in die Grundlagen von .NET: Ralf Westphal: .NET ISBN 3827411858 [2] kompakt; Spektrum, Akademischer Verlag; 2002; Einführung in die Grundlagen von .NET: Hanspeter Mössenböck: Softwareentwicklung mit C#; dpunkt.verlag; 2003; ISBN 3898641260 [3] Probekapitel zur Common Language Runtime: David Chappell: .NET verstehen . Einführung und Analyse; Addison-Wesley; 2002; ISBN 3827320232 http://download.microsoft.com/download/9/2/3/923d72fb-0076-49b6-96c4aac1c255a60e/2023_S87_126OK.pdf [4] Portal zu .NET von Microsoft.com; Bezugsquelle für das .NET-Framework http://msdn.microsoft.com/netframework/ [5] Überblick über die Garbage Collection der CLR: http://msdn.microsoft.com/library/deu/default.asp?url=/library/DEU/cpguide/html/c pconAutomaticMemoryManagement.asp [6] Portal zu WCF von Microsoft.com mit umfangreichen Informationen http://msdn.microsoft.com/webservices/indigo/ - 21 -