Update ohne Panel mit AJAX.PRO

Zugriffe: 6939 starstarstarstarstarstarstarstarstarstar Bewertung:3,8 (10 Bewertungen) 22.11.2009

Kürzlich stolperte ich über einen Beitrag von Roberto Bez, als ich dabei war, einen Blogbeitrag zum Thema Updatepanel & Co zu planen. Es entspricht dabei einer alten Angewohnheit, dass ich zuerst einmal  schaue, ob nicht über dieses Thema schon genug geschrieben wurde, oder ob möglicherweise ein Bedarf da ist. Gut, ich muss eingestehen, zum Thema welches sich mit Ajax.Pro realisieren lässt gibt es im Netz in der Tat nicht viel - im Wesentlichen ja nur Michaels Seite.

Aber zurückkommend auf das eigentliche Thema - dem Updatepanel - da ist immer genug Zündstoff vorhanden. Und so haben sich schon Roberto  und Kristof Zerbe mit dem Thema im Rahmen einer jQuery-Plugin-Entwicklung recht eindrucksvoll befasst. Ich möchte mich heute einer weiteren Variation zu dem Thema zuwenden, natürlich unter Verwendung von Ajax.Pro und etwas Javascript.

Hinsichtlich der grundsätzlichen Fragen zu Ajax.Pro sei zunächst auf die Seite von Michael Schwarz verwiesen als auch den Blogbeitrag, welchen ich hierzu schon einmal verfasst habe. Prinzipiell muss an dieser Stelle gesagt werden, Ajax.Pro ist nicht mehr kompliziert, als die Umsetzung des Ganzen über jQuery und Webservices. Ich halte hier Ajax.Pro sogar noch für wesentlich einfacher, da ich als Entwickler mich auf das Wesentliche konzentrieren kann und der Implementierungsaufwand meiner Meinung nach sogar noch geringer ausfällt. Zudem bietet mir Ajax.Pro die Möglichkeit, .NET-Objekte an den Client zusenden - doch dazu weiter unten mehr.

Zurück zum Updatepanel: seit je her waren in der Webentwicklung Bestrebungen da, möglichst nur Teilbereiche der Seite zu aktualisieren und nicht immer die ganze Seite neu zu laden. Die Anfänge waren wohl die Frames. Dann kamen die IFrames, dann das Remotescripting und ActiveX und nun sind wir beim XmlHttpRequest.

 Für den Benutzer der Webseite als auch den Entwickler ist das Manko des Updatepanels aber offensichtlich - es wird jedes Mal der komplette Page-Lifecycle durchlaufen - ganz dem Motto: "Kauf eine Kuh, wenn du ein Glas Milch brauchst". Aber das war es doch eigentlich, was mit AJAX alles besser werden sollte? Nun gut.

Was passiert in der Regel, wenn man sich für das Updatepanel entscheidet: in der Regel lädt der Entwickler ein Usercontrol wodurch die Seite im Informationsgehalt sich ändert. Das Usercontrol ist dabei meistens ein HTML-Ausschnitt, also nie eine HTML-Seite im eigentlichen Sinne. Was der Entwickler dann in der Regel ebenfalls macht - er lädt die Daten, die für den Benutzer von Bedeutung sind gleich mit. Und da haben wir schon das eigentliche Problem. Letztlich ist doch genau diese Vorgehensweise schlichtweg blöd. Denn was habe ich immer: ich habe immer eine unbekannte Menge an Benutzern denen ich aber allen zum Beispiel immer das gleiche Formular präsentiere. Ist es denn nicht sinnvoller schon an dieser Stelle Daten und Anzeige zu trennen? Roberto und Kristof haben es ebenfalls in ihren Beiträgen klar herausgestellt: JSON ist das, worauf man sich hier konzentrieren sollte. Wenn ich die Daten, welche regelmäßig einen benutzerspezifischen Hintergrund haben, von der Anzeige löse, dann kann ich die Anzeige viel besser cachen. Dem könnte man jetzt kritisch entgegnen, dass man zusätzliche Serveranfragen hat oder, wenn man die Daten holt, kann man das Layout doch auch gleich mitnehmen. Nun, ja, man kann. Aber ich möchte hier letztlich demonstrieren, dass man es auch anders lösen kann. Den Vorteil, welchen ich in dieser Lösung sehe ist schlichtweg, dass ich mich auf das Wesentliche konzentriere - dem Datenaustausch. Damit schaffe ich langfristig eine deutliche Verringerung des Datentransfers in der Client-Server-Kommunikation.

Bei meiner Planung von Webanwendungen mit Ajax-Funktionalität setze ich auf Ajax.Pro. Wie oben schon gesagt, ist es in meinen Augen wesentlich übersichtlicher und der Implementierungsaufwand ist auch deutlich geringer. Dies möchte ich kurz an Hand einer kleinen Gegenüberstellung verdeutlichen:

Roberto und Kristof haben sich für jQuery und folgenden Aufbau entschieden:

Loesung_Roberto

Über einen Defaultparameter wird ein Standardusercontrol benannt und im Weiteren werden die für die jQuery-Implementierung eines Ajax-Aufrufes erforderlichen Parameter und Einstellungen gesetzt.

Mit Ajax.Pro würde ich die Umsetzung zum Beispiel so umsetzen:

Bild5

Worin unterscheiden sich die beiden Ansätze? Bei Ajax.Pro muss ich mich nicht mehr um den dataType und den contentType kümmern. Dies wird von Ajax.Pro automatisch gesetzt, entsprechend dem zurückgegebenen Types. Würde ich mich hier bei der jQuery-Lösung verschreiben, hätte ich ein Problem. Weiter muss ich nicht die Architektur offen legen. Mit Ajax.Pro könnte ich sogar die Methodennamen per Attribute nach außen verschleiern. Da meine Templates allesamt namentlich bekannt sind, habe ich hier einen Enum angelegt, den ich beim Aufruf der Servermethode einfach mitgebe. Den Rest, wo zum Beispiel das Usercontrol am Server liegt, das alles kann ich über den Enum serverseitig auflösen. Und zu guter Letzt - ich habe deutlich weniger Schreibaufwand.

Hinsichtlich des Ladens des Usercontrols, so dass es gerendert werden kann, hat Kristof aus meiner Sicht die bessere Lösung gewählt. Generell ist es immer das gleiche Vorgehen: Eine Instanz der Page-Klasse wird erzeugt. Über die statische Methode LoadControl der Page-Klasse wird das Usercontrol geladen und dem zuvor erzeugten Instanzobjekt hinzugefügt. Über die Excecute-Methode des Server-Objekts des aktuellen HttpContexts wird die Pageinstanz in ein Stringwriter-Objekt übertragen und das Stringwriter-Objekt über die Methode ToString an den Aufrufer zurückgegeben.

Bild6

Würde man dies so belassen, hätte man das Problem, dass das Usercontrol keine ASP-Server-Steuerelemente beinhalten dürfte. Man wäre auf Standard-HTML-Elemente beschränkt und könnte so zum Beispiel auch keine Customcontrols im Usercontrol unterbringen.

Kristof hat diesen Punkt in seiner Variation des jQuery-Plugins des ascxLoader mit berücksichtigt und fügte dem Page-Instanzobjekt noch eine Form-Instanz hinzu. Bevor er Stringwriter an den Aufrufer zurückgibt, bereinigt er diesen, in dem er den Form-Tag und den Viewstate unter Verwendung eines regulären Ausdrucks aus der Zeichenkette entfernt.

Die o.g. Methode würde abschließend daher so ausschauen:

Bild7

Anders als Kristof löse ich das Entfernen des Viewstate und des Form-Tags auf der Clientseite. Man könnte es aber genauso gut auf der Serverseite lösen, so wie es Kristof über reguläre Ausdrücke gemacht hat, was dann den Vorteil hätte, dass man weniger Daten am Ende über die Leitung schickt. Meine clientseitige Lösung sieht indes so aus:

Bild8

Ich erzeuge als erstes ein jQuery-Objekt. Anschließend suche ich den DIV-Tag, der ein input-Element enthält, dessen ID-Attribute den Wert VIEWSTATE beinhaltet. Zum Schluss übernehme ich dann aber nur den innerHTML-Teil des Form-Tags.

Soweit so gut. Eingangs hatte ich angesprochen, dass es doch von Vorteil wäre, man würde beim Usercontrol eine weitere Abstraktion vornehmen, indem man das reine Layout von den benutzerspezifischen Daten noch einmal trennt. Das hat dann den Vorteil, dass ich einmal vom Server abgerufenes Layout sowohl am Server als auch am Client zwischenspeichern kann. Das Beispielprojekt, welches ich zu diesem Beitrag angelegt habe, beinhaltet einen Container, der über einzelne Tabreiter gesteuert wird. Für jeden Tabreiter wird ein individuelles Layout vom Server abgerufen. Wechsle ich nun zwischen den Tabreitern in völliger Aufregung hin un her (diese Leute gibt es wirklich, die sowas machen - ich hab sie kennen gelernt), dann muss ich nicht dauernd den Server bemühen, sondern kann auf die im Javascript gecachten Daten zurückgreifen. Der Performancegewinn ist dabei enorm.

Möchte ich nun die Formularelemente mit Daten füllen, so sende ich nur noch ein Minimum an Daten zwischen Client und Server hin und her. Gerade bei recht komplexen Formularen erscheint mir dieses Vorgehen recht sinnvoll.

Auch auf der Serverseite kann man einmal erledigte Arbeit so abspeichern, dass alle Benutzer einen Vorteil davon haben. So habe ich mich entschlossen, jedes erstmals gerendertes Usercontrol in einer Applicationvariable abzulegen.

Betrachte ich jetzt den Punkt des Datentransfers, so sollte man sich zu jedem Usercontrol eine Objektstruktur überlegen, über die man zwischen Client und Server die Daten austauschen kann. Roberto hat in seinem Beitrag die Möglichkeit des Austauschs komplexer Objekte angesprochen und eine Lösungsmöglichkeiten aufgezeigt. Ajax.Pro bringt diese Möglichkeit gewissermaßen von Haus aus mit - ein Umstand, den ich von Beginn an sehr geschätzt habe und auch heute nicht mehr missen möchte. In diesem Zusammenhang möchte ich auf das Beispielsprojekt zu meinem o.g. Blogbeitrag nur verweisen.

Im heutigen Beispiel übertrage ich zwischen Client und Server lediglich einen String. Das Ganze ist soweit ohnehin noch recht ausbaufähig. Im wesentlichen möchte ich ja nur die prinzipielle Möglichkeiten aufzeigen.

Als Datenquelle habe ich wieder eine kleine XML-Datei genommen, welche einen Ausschnitt aus der Customer-Tabelle der Northwind-Datenbank wieder gibt. Als Contenttemplates habe ich zwei Usercontrols angelegt, welche ich zusätzlich über einen Enum verwalte.

Bild12

Das Rendern der Usercontrols speicher ich mir in einer Applicationvariable ab, so dass diese Arbeit nur einmal getan werden muss. Auch hier ist wieder Spielraum, wie man die Verwaltung der Templates, wenn sie gerendert sind, aufbauen möchte.

Bild13

Clientseitig werden die Template nur vom Server geholt, wenn sie noch nicht im Array, welches ich als Clientcache benutze, vorhanden sind. Im Ergebnis muss ich mich nur noch um die Daten kümmern. Hierzu habe ich mir eine kleine Methode geschrieben. Der Kniff besteht am Ende darin, dass die Formularfelder die gleichen Namen haben, wie die Objekteigenschaften des Datenobjektes.

Bild14

Der Klick auf den Link in der Listenansicht wird über den eventgebundenen Container aufgelöst. Einen sehr ausführlichen Blogbeitrag zu dem Thema der Eventsteuerung hat Michael Schwarz verfasst. Für den Fall, dass das Template für die Listenansicht geladen ist, wird der Datensatzkey zwischengespeichert und anschließend programmatisch der Tab für die Detailansicht aufgerufen.

Bild15

Jetzt beginnt das Prozedere wieder von vorn - das Template wird geladen (vom Server oder aus dem Clientcache) und zu guter Letzt die Daten entsprechend dem zwischengespeicherten Datensatzkey vom Server abgeholt. Die Daten selbst könnte man nun auch am  Client zwischenspeichern, doch müsste man hier unbedingt noch ein Zeitfenster berücksichtigen, wann die Gültigkeit der gecachten Daten verfällt. Beim reinen Formular hat man indes diese Sorgen nicht, da es hier in der Regel an den Daten fehlt.

Das zum Download bereitgestellt Projekt ist ein Visual Studio 2008 Projekt.

 


Live-Demo: (einen Tab anklicken)

  • Detail
  • Liste
AjaxAnimationLade Daten...

Zusammenfassend lässt sich also sagen, dass sowohl über die von Roberto und Kristof aufgezeigten Wege Usercontrols bequem über ein Ajax-Request nachgeladen werden können, als auch über Ajax.Pro sich das Ganze umsetzen lässt. 

Ein weiterer Punkt, der ebenfalls vorher geklärt sein sollte - will man denn in der Form Usercontrols nachladen - ist die Anwendungsstruktur. Es will sehr gut überlegt sein, wie die ganze Webanwendung aufgebaut sein soll und wie sie arbeiten soll.

Viel Spaß beim Ausprobieren


1 Kommentar
unbekannt unbekannt Donnerstag, 14. Januar 2010
toll

Neuen Kommentar verfassen

Bestätigungscode