MSDN Magazin > Home > Ausgaben > 2007 > June >  Wicked Code: Tipps und Tricks zu UpdatePanel
Wicked Code
Tipps und Tricks zu UpdatePanel
Jeff Prosise

Das UpdatePanel-Steuerelement ist im Guten wie im Bösen der Liebling der ASP.NET AJAX-Community. Ich sage „im Guten“, weil UpdatePanel das Rendern von Teilseiten erschreckend einfach macht, und „im Bösen“, weil seine Einfachheit und Benutzerfreundlichkeit auf Kosten der Effizienz und ironischerweise auch der Bandbreite gehen.
Obwohl UpdatePanel den Zauber von AJAX auf Webseiten bringt, liefert es nicht die Effizienz, die wir normalerweise mit AJAX in Verbindung bringen. Haben Sie beispielsweise gewusst, dass dann, wenn ein UpdatePanel-Steuerelement einen asynchronen AJAX-Rückruf zum Server durchführt, um seinen Inhalt zu aktualisieren, die Anforderung alles enthält, was in einem konventionellen ASP.NET-Postback enthalten ist, einschließlich des Ansichtszustands? Die meisten Entwickler nehmen an, dass AJAX den Ansichtszustand beseitigt. Dies ist jedoch bei der UpdatePanel-Marke von AJAX nicht der Fall.
Wenn Sie vorhaben, ein UpdatePanel-Steuerelement zu verwenden, müssen Sie wissen, worauf Sie sich einlassen. In vielen Fällen ist es für eine Anwendung unter dem Gesichtspunkt der Leistung besser, UpdatePanel nicht zu verwenden, sondern stattdessen mit asynchronen Aufrufen von WebMethods oder Seitenmethoden zu arbeiten. Dadurch lässt sich die Datenmenge, die durch die Leitung übertragen wird, um eine ganze Größenordnung oder noch viel mehr reduzieren. Dies stellt aber auch eine fundamentale Umstellung dar, durch die die Aktualisierungen der Benutzeroberfläche vom Entwickler mithilfe von JavaScript auf der Seite explizit gehandhabt werden müssen.
Darüber hinaus sind Diskussionsforen zu ASP.NET AJAX bereits mit Fragen zum Anpassen von UpdatePanel überfüllt. Viele dieser Fragen lassen sich leicht beantworten, sobald Sie von PageRequestManager, der JavaScript-Klasse in der Microsoft®-AJAX-Bibliothek, die die clientseitige Unterstützung von UpdatePanels bereitstellt, erfahren haben.
Nachdem nun ASP.NET AJAX herausgebracht wurde, möchte ich UpdatePanel genauer untersuchen, um herauszufinden, wie Sie es anpassen und optimieren und sogar ohne es auskommen können. Das ist genau das, worum es in diesem Artikel geht.

Aktualisierungshervorhebung
Manchmal können einem die Entwickler von Microsoft schon Leid tun. Wenn sie ihre Arbeit nicht gut genug machen, wird ihnen von der Öffentlichkeit schwer zugesetzt. Manchmal kriegen sie aber auch dann Schelte, wenn sie ihre Arbeit zu gut machen. So erhielt ich zum Beispiel kürzlich eine E-Mail, in der sich ein Kunde darüber beschwerte, dass das UpdatePanel von ASP.NET AJAX etwas zu gut funktioniert.
UpdatePanel macht es ungeheuer einfach, mit all diesem Blinken und Flimmern aufzuräumen, das auftritt, wenn eine ASP.NET-Seite Daten zum Server zurückgibt, und dieses optische Feuerwerk in reibungslose und flimmerfreie Aktualisierungen zu verwandeln. UpdatePanel bewerkstelligt seine Magie, indem es Postbacks in asynchrone Rückrufe (XML-HTTP-Anforderungen) umwandelt und auf dem Client JavaScript verwendet, um den durch das UpdatePanel-Steuerelement eingekapselten Teil der Seite zu aktualisieren. Das Blinken und Flimmern verschwindet, weil der Browser die Seite nicht neu aufbaut, wie dies etwa bei einem Postback geschieht.
Der Kunde hat sich darüber beschwert, dass Benutzer manchmal jenen Teil der Seite, der durch neuen Inhalt aktualisiert wurde, überhaupt nicht bemerken. Seine Frage war ganz einfach: Können die Mitarbeiter des ASP.NET AJAX-Teams UpdatePanel wenigstens ein bisschen flimmern lassen, damit wichtige Aktualisierungen nicht übersehen werden?
Die schlechte Nachricht ist allerdings die, dass das ASP.NET AJAX-Team vermutlich überhaupt nicht daran interessiert ist, UpdatePanels flimmern zu lassen. Schließlich wurde UpdatePanel ja gerade zu dem Zweck entwickelt, dieses Flimmern loszuwerden. Die gute Nachricht lautet, dass Sie ein bisschen AJAX-Magie in den Browser bringen können, um die Aufmerksamkeit auf aktualisierte UpdatePanels zu lenken. Das Geheimnis dafür liegt in der Sys.WebForms.PageRequestManager-Klasse in der Microsoft AJAX-Bibliothek, der Bibliothek der JavaScript-Klassen, die die Clienthälfte von ASP.NET AJAX umfassen. PageRequestManager verwaltet die asynchronen Rückrufe, die von UpdatePanel gestartet werden. Es ist auch für das Aktualisieren des Inhalts innerhalb eines UpdatePanels beim Abschluss eines asynchronen Rückrufs zuständig.
PageRequestManager löst vor und nach einer Aktualisierung Ereignisse im Browser aus. Sie können diese Ereignisse mit JavaScript verknüpfen und Code ausführen, der die Aufmerksamkeit eines Benutzers auf den aktualisierten Inhalt lenkt. Das Schlüsselereignis heißt „pageLoaded“. Dieses Ereignis wird immer dann ausgelöst, wenn die Seite im Browser geladen wird (es entspricht also „Page_Load“ in ASP.NET). Es wird auch immer dann ausgelöst, wenn ein asynchroner Rückruf gestartet wird, weil ein UpdatePanel-Steuerelement abgeschlossen und der Inhalt dieses UpdatePanels aktualisiert wird. Sie können einen JavaScript-Handler für das pageLoaded-Ereignis mit zwei Code-Zeilen registrieren, die auch zu einer einzigen Zeile zusammengefasst werden können:
var prm = Sys.WebForms.PageRequestManager.getInstance();
prm.add_pageLoaded(pageLoaded);
Die erste Zeile erwirbt einen Verweis zum PageRequestManager-Objekt der Seite. Die zweite Zeile registriert eine JavaScript-Funktion namens „pageLoaded“ als Handler für pageLoaded-Ereignisse.
Wenn ein pageLoaded-Ereignishandler aufgerufen wird, erhält er ein Argument vom Typ „Sys.WebForms.PageLoadedEventArgs“, was eine weitere Klasse in der Microsoft-AJAX-Bibliothek darstellt. PageLoadedEventArgs enthält eine Methode namens „get_panelsUpdated“, die Sie aufrufen können, um alle UpdatePanels (sofern vorhanden) aufzuzählen, deren Inhalt gerade aktualisiert wurde. Da ein UpdatePanel standardmäßig nichts weiter als ein DIV auf der Clientseite ist, können Sie JavaScript verwenden, um das DIV blinken zu lassen, hervorzuheben oder eben das zu tun, was auch immer Sie tun möchten, um die Aufmerksamkeit eines Benutzers auf dieses DIV zu lenken.
Der Code in Abbildung 1 zeigt eine Möglichkeit, pageLoaded-Ereignisse dafür zu verwenden, Aktualisierungen hervorzuheben. Immer dann, wenn eine Aktualisierung stattfindet, lässt dieses JavaScript die DOM (Document Object Model)-Elemente, die die aktualisierten UpdatePanels repräsentieren, aufblinken, indem sie drei Mal schnell hintereinander ein- und ausgeblendet werden. Dieses Blinken wird durch eine Hilfsfunktion namens „flashPanels“ durchgeführt, die als Eingabeparameter eine Blinkzahl akzeptiert.
<script type=”text/javascript”>

var prm = Sys.WebForms.PageRequestManager.getInstance();
prm.add_pageLoaded(pageLoaded);

var _panels, _count;

function pageLoaded(sender, args)
{
    if (_panels != undefined && _panels.length > 0)
    {
        for (i=0; i < _panels.length; i++)
            _panels[i].dispose();
    }

    var panels = args.get_panelsUpdated();

    if (panels.length > 0)
    {
        _panels = new Array(panels.length);

        for (i=0; i < panels.length; i++) 
            _panels[i] = new Sys.UI.Control(panels[i]);

        flashPanels(3);
    }
}

function flashPanels(count)
{
    _count = (count << 1) + 1;
        
    for (i=0; i < _panels.length; i++) 
        _panels[i].set_visible(false);

    window.setTimeout(toggleVisibility, 50);
}

function toggleVisibility()
{
    for (i=0; i < _panels.length; i++) 
        _panels[i].set_visible(!_panels[i].get_visible());
        
    if (--_count > 0)
        window.setTimeout(toggleVisibility, 50);
}
</script>
Beachten Sie, wie die Sichtbarkeit eines aktualisierten UpdatePanels aktiviert und deaktiviert wird, um ein Blinken zu erzeugen. Statt direkt auf DOM-Elemente einzuwirken, wrappt der Code die DOM-Elemente, die die UpdatePanels repräsentieren, mit Sys.UI.Control-Objekten. Danach verwendet er die Methoden „set_visible“ und „get_visible“ von Sys.UI.Control, um die Sichtbarkeit ein- und auszuschalten:
_panels[i].set_visible(!_panels[i].get_visible());
Sys.UI.Control ist eine JavaScript-Klasse, die sich in der Microsoft-AJAX-Bibliothek „MicrosoftAjax.js“ befindet. Der Vorteil, die Sichtbarkeit auf diese Weise zu ändern, besteht darin, dass dieser Vorgang browserunabhängig ist. Diese Methode funktioniert in jedem Browser, der ASP.NET AJAX unterstützt, (also praktisch in allen modernen Browsern) gleichermaßen gut. JavaScript-Code dagegen, der direkt auf das Browser-DOM einwirkt, müsste speziell angepasst werden, um in verschiedenen Browsertypen zu funktionieren.

Abbrechen von UpdatePanel-Aktualisierungen
Das pageLoaded-Ereignis ist eines von mehreren Ereignissen, die von der PageRequestManager-Klasse ausgelöst werden, wenn ein UpdatePanel zum Server zurückkehrt, um seinen Inhalt zu aktualisieren. Ein weiteres wichtiges Ereignis, das PageRequestManager auslöst, ist initializeRequest, das ausgelöst wird, bevor ein asynchroner Rückruf stattfindet.
Vor kurzem hat mich jemand gefragt, ob es möglich ist, zur Laufzeit zu entscheiden, ob einem AsyncPostBackTrigger ermöglicht werden sollte, eine UpdatePanel-Aktualisierung auszulösen. Die Antwort lautet „Ja“. Dies wird durch die Verarbeitung von initializeRequest-Ereignissen bewerkstelligt.
Der zweite Parameter, der einem initializeRequest-Handler übergeben wird, ist ein Objekt vom Typ „initializeRequestEventArgs“. Dieses Objekt enthält eine Methode namens „get_postBackElement“, die die Schaltfläche oder das sonstige Element identifiziert, das die Aktualisierung ausgelöst hat. Es enthält auch eine Methode namens „set_cancel“, die Sie verwenden können, um einen Rückruf abzubrechen, bevor er stattfindet. Hier ist ein Beispiel dafür, wie die Methode „set_cancel“ funktioniert:
<script type=”text/javascript”>

var prm = Sys.WebForms.PageRequestManager.getInstance();
prm.add_initializeRequest(initializeRequest);

function initializeRequest(sender, args)
{
    args.set_cancel(!confirm(‘Are you sure?’));
}
</script>
In diesem Beispiel wird vor der Ausführung eines Rückrufs von einem intializeRequest-Handler ein Bestätigungsfenster eingeblendet, in dem der Benutzer gefragt wird, ob die Aktualisierung fortgesetzt werden soll. Wird im Bestätigungsfenster auf „Abbrechen“ geklickt, wird „true“ an set_cancel übergeben und dadurch der Rückruf abgebrochen. Im wirklichen Leben werden Sie wahrscheinlich kein Interesse daran haben, den Benutzer zu einer Bestätigung aufzufordern, bevor eine Aktualisierung durchgeführt wird, aber es könnte nützlich sein, die Möglichkeit zu haben, eine Aktualisierung aufgrund der Bedingungen in anderen Bereichen der Anwendung abzubrechen.
Übrigens ist es auch möglich, asynchrone Rückrufe abzubrechen, nachdem sie ausgeführt wurden, doch bevor sie abgeschlossen werden. PageRequestManager stellt dafür eine Methode namens „abortPostBack“ bereit. Darüber hinaus stellt er auch eine Methode namens „get_isInAsyncPostBack“ zur Verfügung, um zu ermitteln, ob ein asynchroner Rückruf aussteht. Diese Methoden werden häufig zusammen mit UpdateProgress-Steuerelementen verwendet, um eine Abbruchbenutzeroberfläche zu präsentieren.

Mehrere UpdatePanels
Eine Seite kann mehrere UpdatePanels hosten. Wenn ein UpdatePanel auf einer Seite aktualisiert wird, werden standardmäßig auch die anderen UpdatePanels auf dieser Seite aktualisiert. Manchmal ist dies erwünscht, doch meistens ist es nicht notwendig, alle UpdatePanels aktualisieren zu lassen, sobald ein UpdatePanel aktualisiert wird.
Sie können auswählen, welche (und wann) UpdatePanel-Instanzen aktualisiert werden sollen, indem Sie für jedes auf der Seite enthaltene UpdatePanel-Steuerelement die UpdateMode-Eigenschaft auf „Conditional“ (Bedingt) einstellen. Rufen Sie dann, wenn ein UpdatePanel aktualisiert wird und einen serverseitigen Ereignishandler aufruft, für die anderen Panels, die aktualisiert werden sollen, UpdatePanel.Update auf. Dies verringert die Auslastung des Servers, indem die Anzahl der Steuerelemente gesenkt wird, die gerendert werden. Außerdem wird das Datenvolumen in der Antwort verringert, weil UpdatePanels, die nicht aktualisiert werden, nichts zur Antwort hinzufügen.

Aktualisierungen ohne UpdatePanels
Bei AJAX geht es nicht nur um mehr Benutzerfreundlichkeit, sondern auch darum, eine höhere Effizienz in der Leitung zu bieten. Wenn ein herkömmliches ASP.NET-Postback stattfindet, werden alle im Webformular enthaltenen Daten einschließlich des Ansichtszustands im Postback zum Server übertragen. Der Ansichtszustand ist einer der Gründe, aus denen ASP.NET-Seiten (vor allem solche, die DataGrid- und GridView-Steuerelemente verwenden), schwerfällig wirken können. Seiten mit zu viel Ansichtszustand sind für die Leistung eine Katastrophe und kommen in ASP.NET-Anwendungen viel zu häufig vor.
Einer der Vorteile, ASP.NET-Postbacks durch AJAX-Rückrufe zu ersetzen, besteht darin, dass dann, wenn dies richtig gemacht wird, AJAX-Rückrufe nur die Daten übertragen, die übertragen werden müssen. Dies bedeutet, dass sie in diese Übertragung den Ansichtszustand nicht einbeziehen müssen.
Wenn Sie UpdatePanel verwenden, um auf einer Seite flimmerfreie Aktualisierungen durchzuführen, denken Sie möglicherweise, dass Sie damit eine höhere Effizienz erreichen. Schließlich arbeiten UpdatePanels ja mit AJAX, oder etwa nicht? Wenn Sie jedoch den Datenverkehr prüfen, der bei der Aktualisierung von UpdatePanel durch die Leitung fließt, werden Sie leider feststellen, dass Sie nicht viel sparen, jedenfalls nicht beim Senden. Die Ansichtszustandsdaten (und andere Daten), die bei einem Postback normalerweise zum Server übertragen werden, werden auch bei UpdatePanel-Rückrufen übertragen. Was bei einer asynchronen XML-HTTP-Anforderung von einem UpdatePanel zunimmt, ist fast identisch mit dem, was bei einem standardmäßigen ASP.NET-Postback zunimmt. Hier ist das kleine böse Geheimnis von ASP.NET AJAX: Bei UpdatePanel geht es nicht um Effizienz in der Leitung, sondern um die Einfachheit der Verwendung.
Es gibt nicht viel, was Sie tun können, um UpdatePanels effizienter zu machen, aber Sie könnten auf die Verwendung von UpdatePanels völlig verzichten und andere Funktionen von ASP.NET AJAX verwenden, um Inhalte auf Seiten genauso reibungslos und wesentlich effizienter zu aktualisieren. Dies erfordert ein klein wenig mehr Arbeit, aber die Ergebnisse sind es oft wert, denn Sie können dadurch das Datenvolumen, das zwischen Client und Server übertragen wird, beträchtlich reduzieren.
Sie können außerdem die Auslastung Ihres Servers senken. Wenn ein UpdatePanel einen Rückruf zum Server durchführt, durchläuft die Zielseite des Rückrufs einen fast kompletten Lebenszyklus. Die Seite wird instanziiert, die auf der Seite enthaltenen Steuerelemente werden instanziiert, und die im UpdatePanel enthaltenen Steuerelemente werden einem normalen Renderzyklus unterzogen. Schon allein mit dem Aktualisieren eines Teils der Seite ist ein enormer Aufwand verbunden.
Ziehen Sie als Beispiel das Seitenfragment in Abbildung 2 heran. Darin wird eine einfache Benutzeroberfläche bereitgestellt, die es dem Benutzer ermöglicht, eine Postleitzahl einzugeben und auf eine Schaltfläche zu klicken, um die Felder für Stadt und Bundesstaat mit einer Stadt und einem Bundesstaat zu initialisieren (siehe Abbildung 3). Da alle Steuerelemente in einem UpdatePanel gehostet werden, wird der Postback des Button-Steuerelements in einen asynchronen Rückruf umgewandelt und der Ereignishandler (GetCityAndState) wird auf dem Server innerhalb des Rückrufs aufgerufen. GetCityAndState (der Code ist nicht angezeigt) liest die Postleitzahl aus dem PLZ-Textfeld ein, konvertiert sie in eine Stadt und einen Bundesstaat und initialisiert TextBox und DropDownList, die die Stadt und den Bundesstaat repräsentieren. Da das Ganze innerhalb von UpdatePanel geschieht, geht dies reibungslos und flimmerfrei vonstatten.
<asp:UpdatePanel ID=”UpdatePanel1” runat=”server”>
  <ContentTemplate>
    City:<br />
    <asp:TextBox ID=”City” runat=”server” />
    <br /><br />
    State:<br />
    <asp:DropDownList ID=”Region” runat=”server”>
        <asp:ListItem Value=”AL”>Alabama</asp:ListItem>
        <asp:ListItem Value=”AK”>Alaska</asp:ListItem>
        <asp:ListItem Value=”AZ”>Arizona</asp:ListItem>
          ...
        <asp:ListItem Value=”WV”>West Virginia</asp:ListItem>
        <asp:ListItem Value=”WI”>Wisconsin</asp:ListItem>
        <asp:ListItem Value=”WY”>Wyoming</asp:ListItem>
    </asp:DropDownList>
    <br /><br />
    Zip Code:<br />
    <asp:TextBox ID=”ZipCode” runat=”server” />&nbsp;
    <asp:Button ID=”AutofillButton” Text=”Autofill”
      OnClick=”GetCityAndState” runat=”server” />
  </ContentTemplate>
</asp:UpdatePanel>
Abbildung 3 Benutzeroberfläche für Stadt, Bundesstaat und PLZ (Klicken Sie zum Vergrößern auf das Bild)
Hier liegt das Problem. Ein auf diese Weise verwendetes UpdatePanel erhöht die Benutzerfreundlichkeit, trägt aber nur wenig dazu bei, das Volumen an Daten zu senken, das durch die Leitung übertragen wird. Die Auslastung des Servers wird durch das UpdatePanel ebenfalls kaum reduziert, denn bis zu dem Punkt, an dem die Steuerelemente innerhalb des UpdatePanels gerendert werden, ist die Verarbeitung, die auf dem Server durchgeführt wird, mit der Verarbeitung bei einem vollständigen Postback fast identisch. Dies muss auch so sein, denn einer der Vorteile des UpdatePanel-Steuerelements besteht darin, dass serverseitige Ereignishandler wie „GetCityAndState“ innerhalb eines asynchronen Rückrufs nicht anders arbeiten als in einem herkömmlichen Postback. Dies bedeutet, dass auf der Seite enthaltene Steuerelemente instanziiert und initialisiert werden müssen, Zugriff auf den Ansichtszustand haben müssen und so weiter.
Abbildung 4 zeigt, wie dieselbe Funktionalität ohne ein UpdatePanel-Steuerelement implementiert wird. Diesmal ist die Schaltfläche „Autofill“ (AutoAusfüllen) mit einer Javascript-Routine gekoppelt, die eine asynchrone XML-HTTP-Anforderung an eine ASMX-Webmethode namens „GetCityAndState“ auslöst. Der Aufruf erfolgt durch den JavaScript-Proxy namens „ZipCodeService“, der vom Dienstverweis im ScriptManager-Steuerelement generiert wird. GetCityAndState nimmt eine PLZ-Zeichenfolge entgegen und gibt ein Zeichenfolgenarray zurück, in dem zwei Elemente enthalten sind: die entsprechende Stadt und der entsprechende Bundesstaat. Die abschließende Funktion „onGetCityAndStateCompleted“ ruft die Elemente aus dem Array ab und fügt sie in die Felder für die Stadt und den Bundesstaat ein. Äußerlich liefert dies dasselbe Ergebnis, aber im Innern wird dazu ganz anders vorgegangen.
<asp:ScriptManager ID=”ScriptManager1” runat=”server”>
    <Services>
        <asp:ServiceReference Path=”ZipCodeService.asmx” />
    </Services>
    <Scripts>
      <asp:ScriptReference Name=”PreviewScript.js”
Assembly=”Microsoft.Web.Preview” />
    </Scripts>
</asp:ScriptManager>

City:<br />
<asp:TextBox ID=”City” runat=”server” />
<br /><br />
State:<br />
<asp:DropDownList ID=”Region” runat=”server”>
    <asp:ListItem Value=”AL”>Alabama</asp:ListItem>
    <asp:ListItem Value=”AK”>Alaska</asp:ListItem>
    <asp:ListItem Value=”AZ”>Arizona</asp:ListItem>
      ...
    <asp:ListItem Value=”WV”>West Virginia</asp:ListItem>
    <asp:ListItem Value=”WI”>Wisconsin</asp:ListItem>
    <asp:ListItem Value=”WY”>Wyoming</asp:ListItem>
</asp:DropDownList>
<br /><br />
Zip Code:<br />
<asp:TextBox ID=”ZipCode” runat=”server” />&nbsp;
<asp:Button ID=”AutofillButton” Text=”Autofill”
  OnClientClick=”autoFill(); return false;” runat=”server” />

<script type=”text/javascript”>
function autoFill()
{
    var tb = new Sys.Preview.UI.TextBox ($get(‘ZipCode’));
    var zip = tb.get_text();

    if (zip.length == 5)
        ZipCodeService.GetCityAndState (zip,
            onGetCityAndStateCompleted);
}

function onGetCityAndStateCompleted(result)
{
    if (result != null)
    {
        var tb = new Sys.Preview.UI.TextBox ($get(‘City’));
        tb.set_text(result[0]);

        var select =
            new Sys.Preview.UI.Selector ($get(‘Region’));
        select.set_selectedValue(result[1]);
    }
}
</script>
Der Aufruf der ASMX-Webmethode durch den JavaScript-Proxy wird folgendermaßen implementiert:
[ScriptService]
public class ZipCodeService : System.Web.Services.WebService
{
    [WebMethod]
    public string[] GetCityAndState(string zip)
    {
      ...
    }
}
Dies ist in jeder Hinsicht eine standardmäßige Webmethode, abgesehen von der Tatsache, dass der Klasse, der sie angehört, ScriptService statt WebService zugeschrieben wird. ScriptService ist gleichbedeutend mit WebService, bedeutet jedoch zudem, dass die WebMethods des Webdiensts von clientseitigem Skript aufgerufen werden können.
Abgesehen davon, dass ASP.NET AJAX ermöglicht, konventionelle WebMethods als Ziele für XML-HTTP-Anforderungen zu verwenden, unterstützt ASP.NET AJAX auch einen speziellen Webmethodentyp, der als Seitenmethode bezeichnet wird. Seitenmethoden sind WebMethods, die auf Webseiten implementiert werden, also nicht in ASMX-Dateien, sondern in ASPX-Dateien oder Codebehind-Dateien. Seitenmethoden ermöglichen Entwicklern, Endpunkte für XML-HTTP-Rückrufe bereitzustellen, ohne dedizierte Webdienste erstellen zu müssen.
Seitenmethoden müssen öffentliche statische Methoden sein und genau wie WebMethods mit dem WebMethod-Attribut versehen werden. (WebMethods und Seitenmethoden können auch mit dem ScriptMethod-Attribut versehen werden, das zusätzliche Kontrolle darüber bietet, was durch die Leitung geschickt wird.) Auf dem Client werden Seitenmethoden von JavaScript durch den speziellen PageMethods-Proxy aufgerufen.
Im Gegensatz zu Webdiensten erfordern Seitenmethoden keine Dienstverweise. Sie müssen jedoch Seitenmethoden aktivieren, indem Sie die EnablePageMethods-Eigenschaft eines ScriptManager-Steuerelements wie folgt auf „true“ setzen:
<asp:ScriptManager ID=”ScriptManager1” runat=”server”
  EnablePageMethods=”true” />
Seitenmethoden bieten die gleiche Effizienz wie WebMethods. Wenn Seitenmethoden aufgerufen werden, werden Ansichtszustand und andere Eingaben nicht zum Server übertragen. Außerdem können Seitenmethoden aufgerufen werden, ohne eine Seitenobjekt zu instanziieren, da sie statisch sind. Durch den Aufruf einer Seitenmethode wird nicht der Lebenszyklus der Seite aufgerufen, der durch konventionelle ASP.NET-Anforderungen ausgelöst wird.

Webdienst != SOAP und XML
Eines der wichtigsten Merkmale von ASP.NET AJAX ist die Fähigkeit, mithilfe asynchroner XML-HTTP-Anforderungen von Browserclients WebMethods und Seitenmethoden auf einem Server aufzurufen. Wenn ich anderen von dieser Funktionsweise erzähle, ziehe ich jedoch unwillkürlich den Kopf ein wenig ein.
Wenn wir den Begriff „Webdienst“ hören, denken die meisten von uns an SOAP und XML. Normalerweise wird keine dieser Technologien im selben Atemzug mit dem Wort „effizient“ genannt. Sie können zwar WebMethods aus JavaScript heraus mithilfe von ASP.NET AJAX aufrufen. Doch ASP.NET AJAX verwendet nicht SOAP und XML.
Abbildung 5 zeigt, was durch die Leitung fließt, wenn der Webmethodenaufruf in Abbildung 4 ausgeführt wird. Abgesehen von den HTTP-Headern sind die einzigen Daten, die in der Anforderung übertragen werden, die vom Benutzer eingegebene Postleitzahl, und die einzigen Daten, die in der Antwort zurückgegeben werden, bestehen aus einem Zeichenfolgenpaar, das eine Stadt und einen Bundesstaat repräsentiert. Sie werden weder SOAP noch XML (und auch keinen Ansichtszustand) entdecken. Stattdessen wird die Eingabe und die Ausgabe mithilfe von JSON (JavaScript Object Notation) kodiert, was bei weitem nicht so ausführlich ist wie XML und leichter verarbeitet werden kann. Statt SOAP verwenden die Anforderung und die Antwort ein einfaches Protokoll, bei dem es sich im Grunde nur um HTTP handelt. Die Kombination von HTTP und JSON macht ASP.NET AJAX-Aufrufe von WebMethods und Seitenmethoden wesentlich effizienter als herkömmliche Webdienstaufrufe.

Anforderung
 
POST /Ajax/ZipCodeService.asmx/GetCityAndState HTTP/1.1
Accept: */*
Accept-Language: en-us
Referer: http://localhost:1997/Ajax/ZipCodePage.aspx
UA-CPU: x86
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; ...)
Host: localhost:1997
Content-Length: 15
Connection: Keep-Alive
Cache-Control: no-cache

{"zip":"98052"}
Antwort
 
HTTP/1.1 200 OK
Server: ASP.NET Development Server/8.0.0.0
Date: Fri, 29 Dec 2006 21:06:17 GMT
X-AspNet-Version: 2.0.50727
Cache-Control: private, max-age=0
Content-Type: application/json; charset=utf-8
Content-Length: 16
Connection: Close

{"REDMOND", "WA"} 
JSON ist ein vielversprechendes Serialisierungsformat des Branchenstandards. Es ist auch das systemeigene Format, das von ASP.NET AJAX eingesetzt wird. JSON-Serialisierung und -Deserialisierung werden auf der Clientseite durch die Sys.Serialization.JavaScriptSerializer-Klasse der Microsoft-AJAX-Bibliothek unterstützt. Auf dem Server wird diese Unterstützung durch die System.Web.Script.Serialization.JavaScriptSerializer-Klasse bereitgestellt.
Nicht alle Typen sind JSON-kompatibel. JSON kann beispielsweise Objekte mit Zirkelverweisen nicht verarbeiten. Wenn Sie komplexe Datentypen zurückgeben müssen, die nicht JSON-kompatibel sind, können Sie das ScriptMethod-Attribut von ASP.NET AJAX verwenden, um Rückgabetypen in XML zu serialisieren. Dieses Verfahren ist auch bei Methoden nützlich, die XML-Daten zurückgeben, wie folgendes Beispiel zeigt:
[ScriptMethod (ResponseFormat=ResponseFormat.Xml)]
public XmlDocument GetData()
{
  ...
}
Alternativ dazu können Sie benutzerdefinierte JSON-Konverter erstellen und registrieren, die das Serialisieren und Deserialisieren von Typen ermöglichen, die normalerweise nicht JSON-kompatibel sind. Das ASP.NET AJAX January Futures CTP enthält drei derartige Konverter: Einen für DataSets, einen für DataTables und einen für DataRows.

Senden Sie Fragen und Kommentare für Jeff Prosise an  wicked@microsoft.com.


Jeff Prosise schreibt redaktionelle Beiträge für das MSDN-Magazin und ist Verfasser mehrerer Bücher wie z. B. Programming Microsoft .NET (Microsoft Press, 2002). Er ist außerdem Mitbegründer von Wintellect (www.wintellect.com), einem Unternehmen für Softwareberatung und -schulung, das sich auf Microsoft .NET spezialisiert hat.

Page view tracker