André Krämers Blog

Lösungen für Ihre Probleme

Das man mit statischen, oder auch dyanamischen Seiten, die bei jeder Anfrage die komplette Seite neu aufbauen, heute keinen Blumentopf mehr gewinnt, dürfte jedem klar sein. Verwöhnt durch Webanwendungen wie zum Beispiel Google-Maps oder Outlook Web Access erwarten Endanwender Webanwendungen, die einen ähnlichen Bedienkomfort wie Desktop Anwendungen aufweisen.

Als Entwickler solcher Webanwendungen bringt uns dies in die Situation, dass wir unsere Entwicklungstätigkeiten nun nicht mehr rein auf den Server beschränken können, sondern auch auf dem Client aktiv werden müssen, um die hohen Erwartungen unserer Anwender zu erfüllen.

Was “auf dem Client aktiv werden” konkret bedeutet möchte ich in einer kleinen Artikelreihe in meinem Blog beantworten.

Der Client - das unbekannte Wesen

Heutzutage sind eine Reihe Ajax Frameworks verfügbar, die uns die “schmutzige” Arbeit auf dem Weg zur dynamischen Webseite abnehmen wollen. Da es meiner Meinung nach aber nie schaden kann, wenn man weiss was diese magischen Toolsets und Frameworks unter der Haube machen, werden wir heute die Ärmel hoch krempeln und die “Drecksarbeit” auf dem Client selbst erledigen.

Ehe wir los legen, sollten wir zuvor jedoch einen Blick auf die notwendigen Zutaten werfen und kurz klären, worum es sich dabei im einzelnen handelt.

  1. JavaScript

    Das J in AJAX. Eine von vielen Entwicklern zu unrecht gefürchtete und/oder belächelte Client Script Sprache ;-) Der Scriptcode wird entweder direkt in eine Seite eingebettet, oder aber in eine externe Datei ausgelagert. JavaScript wird zur Manipulation des DOM genutzt

  2. das Document Object Model (DOM) des Browsers

    Das DOM des Browsers ist eine Schnittstelle, die den Zugriff auf das zugrundeliegende (X)HTML Dokument bereitstellt. Über das DOM habe ich die Möglichkeit,Aussehen und Struktur der einer Webseite zu verändern.

  3. das XMLHttpRequest Objekt

    Eines der Objekte des window Objekts des Browsers(zumindest in modernen Browsern. Andernfalls ein ActiveX Objekt). Es ermöglicht einem Script das Absetzen einer (asynchronen) Anfrage an einen Webserver.

Im Überblick sieht das Zusammenspiel der drei Komponenten ungefähr so aus:

Zusammenspiel zwischen JavaScript, DOM und XMLHttpRequest

Los gehts!

Wir wissen zwar jetzt, was wir alles brauchen, allerdings fehlt immer noch die Antwort, wie die Komponenten nun genutzt werden müssen, um AJAX in die eigene Webseite zu bekommen.

Starten wir dazu mit einem kleinen und sehr einfachen Beispiel.

Wir erstellen eine einfache ASPX Seite, die aus einem Link und einem Platzhalter Bereich bestehen soll. Sobald der Anwender auf den Link klickt, soll dieser Platzhalter mit dem Inhalt einer statischen Datei, welche auf dem Server liegt, gefüllt werden.

Der zugehörige HTML Code der ASPX Seite sieht wie folgt aus:

<form id="form1" runat="server">
   <div>
      <p>
        <a href="#">Hier klicken zum Request einer statischen Datei </a>
      </p>
   </div>
   <div id="content">
      Bitte klicken Sie den Link, damit dieser Bereich gefüllt wird.
   </div>
</form>

Der Link, welcher später die Ajax Aktion initiieren soll, wird in den Zeilen 5 und 6 definiert. Der Bereich welcher später ersetzt werden soll, ist der Inhalt des DIV Tags aus Zeile 9.

Noch ist das ganze jedoch nicht sonderlich dynamisch. Dazu benötigen wir noch etwas JavaScript:

<script type="text/javascript">
  var xmlHttp;
  window.onload = function () {
      initializeXmlHttp();
  }
  function initializeXmlHttp() {
      if (window.XMLHttpRequest) {
          // IE7, IE8, Mozilla, Safari, Opera
          xmlHttp = new XMLHttpRequest();
      } else if (window.ActiveXObject) {
          try {
              xmlHttp = new ActiveXObject("Microsoft.XMLHTTP"); //IE 5.x, 6
          } catch (e) {
              alert('Ajax Zugriffe sind aufgrund der aktuellen Sicherheitseinstellungen leider nicht möglich');
          }
      }
  }
  function sendAjaxRequest(url) {
      if (xmlHttp) {
          xmlHttp.open("GET", url, true);
          xmlHttp.onreadystatechange = requestFinished;
          xmlHttp.send(null);
      }
  }
  function requestFinished() {
      if (xmlHttp.readyState == 4) {
          if (xmlHttp.status == 200) {
              var contentDiv = document.getElementById('content');
              contentDiv.innerHTML = xmlHttp.responseText;
          }
      }
  }
</script>

Das Script deklariert zunächst in Zeile 2 eine Variable, die einen Verweis auf das XMLHhtpRequest Objekt hält. Wie zuvor beschrieben ermöglicht dieses das Absetzen einer asynchronen Abfrage an den Server.

Die Funktion initializeXmlHttp ab Zeile 7 füllt dieses Objekt nun mit Leben. Der Code sollte recht selbsterklärend sein. Zeile 8 prüft, ob das XMLHttpRequest Objekt am window Objekt hängt. Falls ja, kann ein neues XMLHttpRequest Objekt erstellt werden. Ist dies nicht der Fall, muss es als ActiveX Objekt erstellt werden.

Die Funktion sendAjaxRequest ab Zeile 20 setzt die eigentliche Abfrage ab. Dazu prüft Sie in Zeile 21 zuerst, ob die Variable xmlHttp initialisiert werden konnte. Wäre dies nicht der Fall, könnte keine Abfrage abgesandt werden. Anschließend wird in Zeile 22 eine asynchrone Verbindung geöffnet mit der Methode *open *geöffnet. Diese Methode erhält als Parameter die Methode (“GET” oder “POST”), die URL, sowie ein Flag, ob die Anfrage asynchron abgesetzt werden soll.

Zeile 23 gibt eine CallBack-Funktion an (in unserem Fall requestFinished), die aufgerufen werden soll, sobald eine Antwort auf die Anfrage zurück gekommen ist.

Zeile 24 sendet die Anfrage nun schließlich ab.

Die Funktion requestFinished ab Zeile 28 verarbeitet die Antwort des Webservers. Da eine Anfrage verschiedene Phasen durchlebt, prüft die Funktion in Zeile 29 anhand der Eigenschaft readyState ab, ob die Anfrage tatsächlich komplett beendet wurde.

Da zu Ende nicht immer “hat auch geklappt” heißen muss, wird in der nächsten Zeile geprüft, ob die Anfrage auch erfolgreich beendet wurde (HTTP Statuscode 200).

Die eigentliche Verarbeitung findet nun in den Zeilen 31 und 32 statt. Zeile 31 holt sich eine Referenz auf den zu ersetzenden Bereich (unser Div mit der ID Content). Zeile 32 überschreibt diesen Inhalt schlussendlich mit der Antwort des Servers.

Damit das ganze auch funktioniert muss die Funktion sendAjaxRequest aus Zeile 20 noch aus unserem HTML Code heraus aufgerufen werden. Dazu erweitern wir unseren Link aus den Zeilen 5/6 einfach um das Attribut onclick.

<a href="#" onclick="sendAjaxRequest('static.html');">Hier klicken zum Request einer statischen Datei </a>

Ausgeführt sieht das ganze dann wie folgt aus:

Erster Aufruf der SeiteNach Aufruf des Links

Ganz nett …

wir wissen nun also, wie wir statische Dateien nachladen können, aber steht das X in AJAX nicht für XML Webservices?

Genau! Deshalb habe ich das Demoprojekt auch um einen kleinen Webservice mit zwei sinnlosen Methoden erweitert:

public class AjaxDemoService: System.Web.Services.WebService
{

  [WebMethod]
  public string HelloWorld()
  {
    return "Hello World";
  }

  [WebMethod]
  public string Echo(int number)
  {
    return string.Format("Sie haben {0} eingegeben.", number);
  }
}

Wie rufen wir einen solchen Service nun aber per JavaScript auf?

Die Antwort findet sich relativ schnell, wenn man die URL des Webservices im Browser eingibt. In der nun erscheinenden Seite werden sämtliche Methoden des Webservices aufgelistet. Ein Klick auf eine dieser Methoden verrät schlussendlich, wie die Methode aufgerufen werden muss. Im Beispiel der Methode HelloWorld sieht die Ausgabe für eine HTTP Post Anfrage zum Beispiel wie folgt aus:

Beschreibung des POST Aufrufs der Webservice Methode

Für die Methode Echo wird folgende Ausgabe produziert:

4_echo_http_post

Im Vergleich zu unserer bisherigen Vorgehensweise beim dynamischen Nachladen der statischen Datei fällt auf, dass die Methode, über die die Anfrage gestartet wird, nun nicht mehr GET ein kann, sondern POST sein muss.

Außerdem wird nun auch ein bestimmter Content-Type, nämlich application/x-www-form-urlencoded benötigt. Speziell bei der Methode Echo fällt auf, dass außerdem nun auch Daten mit an den Server gesendet werden müssen.

Um die veränderten Anforderungen abdecken zu können, erweitere ich das bestehende JavaScript um eine neue Funktion:

function postAjaxRequest(url, data) {
   if (xmlHttp) {
     xmlHttp.open("POST", url, true);
     xmlHttp.onreadystatechange = requestFinished;
     xmlHttp.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
     xmlHttp.send(data);
   }
}

Die neuen Funktion, postAjaxRequest ähnelt der vorherigen Funktion sendAjaxRequest. Die veränderten Anforderungen ließen sich relativ einfach integrieren. In Zeile 3 wurde aus einem GET ein POST. In Zeile 5 wird der zusätzlich benötigte Content-Type gesetzt. In Zeile 6 wird der Methode send nun nicht mehr fix null als Datenparameter übergeben. Stattdessen wird das neue Argument data weiter gereicht.

Der HTML Code musste auch nur unwesentlich erweitert werden. Er erhält zwei neue Links zum Aufruf der beiden Webmethoden:

<a href="#" onclick="postAjaxRequest('AjaxDemoService.asmx/HelloWorld', null);">
  Hier für Hello World WebService klicken
</a>
<br />
<a href="#" onclick="postAjaxRequest('AjaxDemoService.asmx/Echo', 'number=1');">
  Hier für Echo WebService klicken
</a>

Das Ergebnis sieht anschließend wie folgt aus:

Abbildung zeigt den Rückgabewert des Hello World Webservices Abbildung zeigt die Rückgabe des Echo Web Services

Fazit

Ajax in eine Webanwendung zu integrieren ist aus technischer Sicht nicht sonderlich schwierig. Der vorliegende Blog Post hat gezeigt, dass sich selbst ohne “magische” Frameworks mit wenigen Zeilen JavaScript Ajax Funktionalitäten integrieren lassen. Natürlich ist die gezeigte Implementierung nur sehr rudimentär. So wurde das zurückgegeben XML des Webservices zum Beispiel noch nicht geparsed und es fand außerdem so gut wie keine Fehlerbehandlung statt. Dieses in das Beispiel zu integrieren hätte den Rahmen eines Blogposts jedoch vollständig gesprengt. Außerdem gibt es genau aus diesen Gründen auch bereits fertige Frameworks, wie ASP.NET AJAX oder jQuery, die einem genau diese Detailarbeit abnehmen.

Ehe man ein solches Framework einsetzt, sollte man jedoch die Grundlagen dessen kennen, was hinter den Kulissen geschieht. Und genau diese Grundlagen haben wir in diesem Blog Post geschaffen.

Das vollständige Beispiel werde ich übrigens am Wochenende zum Download bereit stellen.

Es gibt 3 Kommentare

Comment by GENiALi
Von | 29.10.2011 21:11
Sehr gut. Freue mich schon auf den nächsten. Ich habe mir bis lang noch geweigert AJAX oder ASP.NET im grossen Stiel anzuwenden. Aber meine Frau lässt mir über kurz oder lang keine Wahl mehr. :-)
Comment by André Krämer
Von | 29.10.2011 21:11
Freut mich, dass dir der Eintrag gefallen hat. Vielen Dank für das positive Feedback. Der nächste Teil sollte spätestens Ende der Woche online gehen.Eines interessiert mich natürlich brennend: Wieso lässt dir deine Frau keine andere Wahl als ASP.NET und AJAX zu nutzen ;-) ???
Comment by Rene Drescher-Hackel
Von | 29.10.2011 21:11
das X im Ajax ist aber nicht mehr zeitgemäß - das bessere Format ist inzwischen JSON