Language: Deutsch English















Last Update: 2017 - 07 - 09





Wenn der Viewstate zur Qual wird... (ASP.NET Datagrid)

Ich setze eigentlich voraus, dass der geneigte Leser über den grundsätzlichen Sinn und die genaue Funktionsweise des Viewstate in ASP.NET-WebForms informiert ist, bzw. sich anderweitig (z.B. in den unten angeführten Links) informieren wird. Daher hier nur ein kurzer Überblick über den Viewstate an sich, soweit es mir im Rahmen dieses Artikels erforderlich erscheint.

Viewstate? Häh?

Ein wesentlicher Nachteil der konventionellen Entwicklung vom Webapplikationen ist, dass das HTTP-Protokoll keine direkte Möglichkeit bietet, um den Zustand einer Applikation in irgendeiner Weise zu speichern. Zusammen mit dem Fakt, dass nur Programmcode, der serverseitig ausgeführt wird, wirklich unabhängig von dem verwendeten Client (Webbrowser) ist, und das ist ja ein wesentliches Merkmal von erfolgreichen Webapplikationen, und daher für jede Codeausführung eine neue Anfrage an den Webserver erforderlich ist, stellt das eine gravierende Einschränkung bzw. einen großen Arbeitsaufwand für den Entwickler jeder komplexerere Webapplikation dar.

Mit Cookies und Sessions wurden schon in früheren Entwicklungstechnologien Ansätze geschaffen die es dem Entwickler einfacher machen, Zustände seiner Applikation zu speichern. Dennoch blieb es mühsame Handarbeit für den Entwickler damit den Zustand der GUI, in erster Linie die Werte in den einzelnen Steuerelementen, über die einzelnen Requests an den Server hinweg persistent zu machen. Außerdem werden diese Technologien zwar von fast allen Webbrowsern unterstützt, aber oft hat der Benutzer die Möglichkeit, sie zu deaktivieren.

Eine der wesentlichen Neuerung des ASP.Net-Frameworks in der Webentwicklung ist der Viewstate, der genau dieses Problem adressiert. Denn damit ist die Funktionalität um die aktuellen Eigenschaften der GUI-Controls persistent zu machen, direkt in das Framework integriert und kann vom Entwickler genutzt werden, ohne dass er eigenen Code dazu schreiben muss. Der Viewstate ist als ein verstecktes (hidden) Formularfeld im ASP.Net-Form implementiert, das die Eigenschaften aller auf dem Formular vorhanden (ASP.Net-)Controls als Base64-codiereten Textstring enthält. Auf dem Webserver verarbeitet das ASP.Net-Framework bei jedem Request diesen Textstring und setzt automatisch die Eigenschaften aller Controls auf den darin definierten Wert. Exzellent, das ist eine gewaltige Arbeitsersparnis bei der Entwicklung von komplexen Webapplikationen!

Leider hat dieser Ansatz auch einen Nachteil, der, abhängig von dem jeweiligen Szenario, durchaus sehr gravierend sein kann. Bei jedem Aufruf der Webseite wird zusätzlich zu den eigentlichen Seiteninhalten auch der Viewstate vom Server zum Client bzw. vom Client zum Server gesendet. Abhängig von der verfügbaren Bandbreite und der Menge der Daten kann das zu einem echten Performanceproblem werden. Bei einem einfachen Webform mit ein paar Textboxen oder einer Anwendung die ausschließlich innerhalb eines Intranets mit großer Bandbreite genutzt wird, kann man dieses Problem meist getrost ignorieren, aber bei einer Anwendung, die nicht in diesen Rahmen passt, sollte man sich mindestens dieses potentiellen Problems bewusst sein.

Das ASP.NET Datagrid - jetzt tut's weh!

Einen besonderen (Problem-)Fall stellt in diesem Kontext das ASP.Net-Datagrid dar. Es liegt in der Natur eines Datagrids, dass darin oft eine größere Anzahl an Spalten und Zeilen dargestellt wird. Jede einzelne Zelle des ASP.Net-Datagrids enthält nun jedoch auch ein ASP.Net-Control, dass die jeweiligen Daten darstellt und für das der Viewstate gespeichert, und wie oben beschrieben, immer zwischen Client und Server hin- und hergesendet wird. Wenn der Client über eine langsame Verbindung, z.B. ein 56k-Modem angebunden ist, können diese zusätzlichen Daten schnell zu einer unerträglichen Qual werden. Es sollte also im Interesse des Entwicklers liegen hier das Volumen des Viewstates auf das unbedingt erforderliche Minimum zu reduzieren.

Wenn die Daten in dem Datagrid sowieso ausschließlich zum Lesen angezeigt werden, ist es sehr einfach dies zu erreichen. Man kann dann den Viewstate für das gesamte Datagrid einfach komplett deaktivieren, indem man die EnableViewstate-Property des Datagrids einfach auf "false" setzt. - Leider sind die Ereignisse des Datagrids auch vom Viewstate abhängig und sobald der Viewstate für das Datagrid deaktiviert ist, wird kein einziges Ereignis des Datagrids mehr in der gewohnt bequemen Weise ausgelöst.

Eine recht häufig empfohlener Ansatz das Problem mit dem voluminösen Viewstate des Datagrids zu lösen und gleichzeitig die Events des Datagrids zu behalten ist, nach dem Databind-Event des Datagrids die EnableViewstate-Property für jede Zeile des Datagrids zu deaktivieren.

  foreach(DataGridItem dgi in DataGrid1.Items) 
  {
    dgi.EnableViewState = false;
  }

Damit wird der Viewstate für alle Zeilen des Datagrids und damit für alle Controls die die Daten darstellen deaktiviert. Theoretisch ist dies die Lösung für das Problem, praktisch jedoch lässt dieser Ansatz eine Tatsache unberücksichtigt. Häufig benötigt man für die Verarbeitung des Edit-Events des Datagrids wenigstens den eindeutigen Schlüssel, der die angewählte Zeile identifiziert. Der einfachste Weg diesen Wert zu ermitteln ist, aus dem entsprechenden Control in der betroffenen Zeile des Datagrids. Wenn aber der Viewstate für das komplette DatagridItem deaktiviert wurde, wie der Vorschlag oben suggeriert, ist dieser Wert über ein e.Item.Cells(eineZelle).Controls(0) nicht mehr zu ermitteln, da ja das Datagrid beim Postback zum Server seinen vorherigen Zustand verloren hat.

Meine Lösungsvorschlag für das Viewstate-Problem ist daher ein ähnlicher, aber etwas abgewandelter Ansatz. Anstelle den Viewstate für das komplette DatagridItem zu deaktivieren, schlage ich vor, den Viewstate für alle Cell-Objekte innerhalb des DataGridItems zu deaktivieren außer der einen Zelle, die den eindeutigen Schlüssel für die angezeigten Datensätze enthält. Das kann man einfach erreichen, indem nach dem DataBind des Datagrids, aber vor dem Rendern der Page eine Methode, ähnlich der folgenden aufruft.

	private void disableDGIViewState() 
	{
		foreach(DataGridItem dgi in dasDataGrid.Items) 
		{
			foreach (TableCell tc in dgi.Cells)
				tc.EnableViewState = false;

			dgi.Cells[indexIDSpalte].EnableViewState = true;
		}
	}

Da man irgendwo in der Page sowieso den Code hat, um das Datagrid aus einer Datenbank, einer anderen Datenquelle oder dem Cache/Session zu füllen, muss man nur diesen Code zum Füllen des Datagrids erneut aufrufen und kann sich, mittels der eindeutigen ID aus dem Viewstate, wieder direkt auf die Elemente im Datagrid beziehen.

Mit diesem Ansatz kann man somit, zwar unter erhöhtem Ressourceneinsatz auf dem Server, das Problem des voluminösen Viewstates des Datagrids drastisch entschärfen ohne ganz auf die einfachere, weniger aufwendige Entwicklung unter Nutzung des Viewstates verzichten zu müssen.

Dieser Ansatz ist sicherlich keine silver Bullet zur Verbesserung der Performance von Webapplikationen mit Datagrid, da man immer im Auge behalten sollte, dass das reduzierte Datenvolumen von Request/Response mit höheren Ressourcenverbrauch auf dem Server (entweder RAM für Caching, oder CPU+ RAM für Datenbankabfragen) erkauft werden muss. Dennoch ist bisher in allen Fällen in denen ich diesen Ansatz praktisch eingesetzt habe die subjektiv wahrgenommene Performance beim User deutlich besser als mit der normalen Nutzung des Viewstates. - Wenn das einmal anders ist, sollte auch noch bedenken, dass sich CPU und RAM im Server meist einfacher an höhere Anforderungen anpassen lassen, als die Bandbreite der User.

Weiterführende Links

Eine umfassende, aber knappe Präsentation zum ASP-NET Viewsstate als PDF-Dokument, verfasst von Fritz Onion.
http://www.mainebytes.org/download/viewstate.pdf

Ein sehr gute Erläuterung des Viewstate mit sehr viel Beispielcode von Susan Warren (Program Manager ASP.NET bei MS)
http://msdn.microsoft.com/library/en-us/dnaspnet/html/asp11222001.asp

Daniel Fruzynski beschreibt in dem folgendem Artikel einenen anderen Ansatz den Viewstate des Datagrids zu reduzieren.
http://www.codeproject.com/aspnet/DataGridViewState.asp

Share this article: Share on Facebook Tweet Share on LinkedIn Share on XING

Abonniere meinen Newsletter

*

Ich werde Deine Email-Addresse niemals weitergeben. Du kannst den Newsletter jederzeit abbestellen.



© 1999 - 2017 by Philipp Stiefel