Ein mundgerechtes Stück ASP.NET ViewState
Wenn ich neue ASP.NET-Seitenentwickler treffe und mich mit ihnen unterhalte, lautet eine ihrer ersten Fragen normalerweise "Was ist eigentlich ViewState?". Und häufig entdecke ich in ihren Stimmen dieselbe schaurige Faszination, als wenn mir ein Kellner eines exotischen Restaurants einen Teller mit bisher unbekanntem Essen vorsetzt. Irgend jemand denkt, es sei gut, sonst würde der Kellner es nicht servieren. Also probiere ich es und mag es vielleicht sogar, obwohl es seltsam aussieht.
Auf dieser Seite
Antwort: ViewState behält den Status der Benutzeroberfläche einer Webseite bei
Größerer Nutzen von ViewState
Weniger Nutzen von ViewState
Mehr Sicherheit für ViewState
Zusammenfassung
Das Gleiche gilt für ViewState. Wenn Sie sich erst einmal an das Aussehen gewöhnt haben, werden Sie in vielen Situationen erfreut sein, ViewState in Ihrer ASP.NET-Anwendung verwenden zu können, denn mit ViewState können Sie mit weniger Code wesentlich mehr erzielen. Aber manchmal möchten Sie ViewState auch am liebsten auf dem Teller zurücklassen. Ich werde beide Fälle analysieren, aber zunächst beantworte ich die Frage, was ViewState eigentlich ist.
Antwort: ViewState behält den Status der Benutzeroberfläche einer Webseite bei
Das Web ist statusfrei, und die ASP.NET-Seiten sind es ebenfalls. Sie werden bei jedem Roundtrip zum Server instanziiert, ausgeführt, gerendert und gelöscht. Als Webentwickler können Sie mit Hilfe von bekannten Techniken wie Statusspeicherung auf dem Server im Sitzungsstatus oder Rückübertragung einer Seite eine Statusbehaftung hinzufügen. Nehmen Sie als Beispiel das Anmeldeformular aus Abbildung 1.
Abbildung 1. Wiederherstellen von bereitgestellten Formularwerten
Wie Sie feststellen, habe ich einen ungültigen Wert beim mitzubringenden Essen eingetragen. Dieses Formular, wie viele andere Webformulare auch, zeigt eine hilfreiche Fehlermeldung sowie ein Sternchen neben der falschen Eingabe an. Außerdem bleiben alle gültigen Eingaben, die ich in den anderen Textfeldern und Dropdownlisten gemacht habe, im Formular erhalten. Dies ist zum Teil deswegen möglich, weil HTML-Formularelemente ihre aktuellen Werte im HTTP-Header vom Browser an den Server übertragen. Sie können ASP.NET-Ablaufverfolgung verwenden, um Formularwerte anzuzeigen, die - wie Abbildung 2 zeigt - zurückübertragen werden.
Abbildung 2. In HTTP-Formularen bereitgestellte Werte, wie sie von der ASP.NET-Ablaufverfolgung angezeigt werden
Vor Einführung von ASP.NET lag das Wiederherstellen von Werten in Formularfeldern mittels zahlreicher Rückübertragungen ausschließlich in der Hand der Webseitenentwickler. Diese mussten die Werte einzeln aus dem HTTP-Formular auswählen und sie zurück in die Felder setzen. ASP.NET hingegen kann diese Aktion automatisch ausführen und erübrigt somit eine Menge lästiger Arbeit und viel Code für Formulare. Aber das ist nicht ViewState.
ViewState ist die Technik, die ASP.NET anwendet, um Statuswerte von Serversteuerelementen zu verfolgen, die andernfalls nicht als Teil des HTTP-Formulars zurückübertragen werden würden. Text beispielsweise, der von einem Label-Steuerelement angezeigt wird, wird standardmäßig in ViewState gespeichert. Als Entwickler können Sie Daten nur beim ersten Laden der Webseite binden oder das Label-Steuerelement programmtechnisch setzen. Bei nachfolgenden Rückübertragungen füllt ViewState das Label selbsttätig aus. Der Vorteil von ViewState liegt nicht nur in weniger Arbeitsaufwand und weniger Code, sondern häufig auch in weniger Roundtrips zur Datenbank.
Funktionsweise von ViewState
ViewState hat nichts mit Zauberei zu tun. Es handelt sich um ein verborgenes Formularfeld, das vom ASP.NET-Seitenframework verwaltet wird. Wenn ASP.NET eine Seite ausführt, werden die ViewState-Werte aus der Seite und sämtliche Steuerelemente zusammengefasst und als eine einzige codierte Zeichenfolge formatiert und anschließend dem Wertattribut des verborgenen Formularfelds zugewiesen (speziell <input type=hidden>). Da das verborgene Formularfeld Teil der an den Client gesendeten Seite ist, wird der ViewState-Wert temporär im Browser des Clients gespeichert. Wenn der Client die Seite an den Server zurücküberträgt, wird die ViewState-Zeichenfolge ebenfalls zurückübertragen. Sie finden das ViewState-Formularfeld und den Rückübertragungswert in Abbildung 2.
Bei der Rückübertragung analysiert das ASP.NET-Seitenframework die ViewState-Zeichenfolge und füllt die ViewState-Eigenschaften für einzelne Seiten und Steuerelemente aus. Die Steuerelemente ihrerseits verwenden die ViewState-Daten, um ihren früheren Status wiederherzustellen.
Drei weitere, nützliche Kleinigkeiten zu ViewState sollten Sie wissen.
-
Auf Ihrer ASPX-Seite müssen Sie über ein serverseitiges Formulartag (<form runat=server>) verfügen, um ViewState verwenden zu können. Ein Formularfeld ist erforderlich, damit das verborgene Feld, das die ViewState-Daten enthält, zum Server zurückübertragen werden kann. Es muss ein serverseitiges Formular sein, damit das ASP.NET-Seitenframework das verborgene Feld hinzufügen kann, wenn die Seite auf dem Server ausgeführt wird.
-
Die Seite selbst speichert ungefähr 20 Byte an Daten in ViewState. Diese dienen bei der Rückübertragung zum Verteilen der PostBack-Daten und der ViewState-Werte auf die richtigen Steuerelemente. Selbst wenn ViewState also für die Seite oder Anwendung deaktiviert ist, können Sie trotzdem einige restliche Bytes in ViewState anzeigen.
-
Falls eine Seite nicht zurückübertragen wird, können Sie ViewState von der Seite entfernen, indem Sie das serverseitige <form>-Tag unterdrücken.
Größerer Nutzen von ViewState
ViewState ist ein hervorragendes Verfahren, um den Status eines Steuerelements in den Rückübertragungen zu verfolgen, da ViewState keine Serverressourcen belegt, keinen Timeout verursacht und mit anderen Browsern zusammenarbeitet. Wenn Sie Steuerelemententwickler sind, sollten Sie hierzu Maintaining State in a Control (in Englisch) lesen.
Seitenentwickler profitieren in ähnlicher Weise von ViewState. Gelegentlich enthalten Ihre Webseiten Benutzeroberflächen-Statuswerte, die nicht von einem Steuerelement gespeichert werden. In ViewState können Sie Werte mit Hilfe einer Programmiersyntax verfolgen, die ähnlich der Syntax für Sitzungen und Cache ist:
[Visual Basic]
' In ViewState speichern
ViewState("SortOrder") = "DESC"
' Aus ViewState auslesen
Dim SortOrder As String = CStr(ViewState("SortOrder"))
[C#]
// In ViewState speichern ViewState["SortOrder"] = "DESC"; // Aus ViewState auslesen string sortOrder = (string)ViewState["SortOrder"];
Beispiel: Sie möchten eine Elementliste auf einer Webseite anzeigen, und jeder Benutzer möchte die Liste unterschiedlich sortieren. Die Liste der Elemente ist statisch. Somit können die Seiten mit demselben zwischengespeicherten Datensatz verbunden werden, die Sortierreihenfolge ist jedoch ein kleiner Teil des benutzerspezifischen Oberflächenstatus. ViewState eignet sich hervorragend für die Speicherung dieses Wertetyps. So sieht der Code aus:
[Visual Basic]
<%@ Import Namespace="System.Data" %>
<HTML>
<HEAD>
<title>ViewState für Statuswerte der Seitenbenutzeroberfläche</title>
</HEAD>
<body>
<form runat="server">
<H3>
Speichern des Nicht-Steuerelement-Status in ViewState
</H3>
<P>
Dieser Beispielcode speichert die aktuelle Sortierreihenfolge
für eine statische Datenliste in ViewState.<br>
Klicken Sie auf den Link im Spaltenheader, um die Daten nach diesem Feld zu sortieren.<br>
Klicken Sie erneut auf diesen Link, um die Sortierreihenfolge umzudrehen.
<br><br><br>
<asp:datagrid id="DataGrid1" runat="server"
OnSortCommand="SortGrid" BorderStyle="None" BorderWidth="1px"
BorderColor="#CCCCCC" BackColor="White" CellPadding="5" AllowSorting="True">
<HeaderStyle Font-Bold="True" ForeColor="White"
BackColor="#006699">
</HeaderStyle>
</asp:datagrid>
</P>
</form>
</body>
</HTML>
<script runat="server">
' SortField-Eigenschaft wird in ViewState verfolgt
Property SortField() As String
Get
Dim o As Object = ViewState("SortField")
If o Is Nothing Then
Return String.Empty
End If
Return CStr(o)
End Get
Set(Value As String)
If Value = SortField Then
' wie in aktueller Sortierdatei, Sortierreihenfolge umkehren
SortAscending = Not SortAscending
End If
ViewState("SortField") = Value
End Set
End Property
' SortAscending-Eigenschaft wird in ViewState verfolgt
Property SortAscending() As Boolean
Get
Dim o As Object = ViewState("SortAscending")
If o Is Nothing Then
Return True
End If
Return CBool(o)
End Get
Set(Value As Boolean)
ViewState("SortAscending") = Value
End Set
End Property
Private Sub Page_Load(sender As Object, e As EventArgs) Handles MyBase.Load
If Not Page.IsPostBack Then
BindGrid()
End If
End Sub
Sub BindGrid()
' Daten abrufen
Dim ds As New DataSet()
ds.ReadXml(Server.MapPath("TestData.xml"))
Dim dv As New DataView(ds.Tables(0))
' Sortierfilter und -richtung anwenden
dv.Sort = SortField
If Not SortAscending Then
dv.Sort += " DESC"
End If
' Raster binden
DataGrid1.DataSource = dv
DataGrid1.DataBind()
End Sub
Private Sub SortGrid(sender As Object, e As DataGridSortCommandEventArgs)
DataGrid1.CurrentPageIndex = 0
SortField = e.SortExpression
BindGrid()
End Sub
</script>
[C#]
<%@ Page Language="C#" %>
<%@ Import Namespace="System.Data" %>
<HTML>
<HEAD>
<title>ViewState für Statuswerte der Seitenbenutzeroberfläche</title>
</HEAD>
<body>
<form runat="server">
<H3>
Speichern des Nicht-Steuerelement-Status in ViewState
</H3>
<P>
Dieser Beispielcode speichert die aktuelle Sortierreihenfolge
für eine statische Datenliste in ViewState.<br>
Klicken Sie auf den Link im Spaltenheader, um die Daten nach diesem Feld zu sortieren.<br>
Klicken Sie erneut auf diesen Link, um die Sortierreihenfolge umzudrehen.
<br><br><br>
<asp:datagrid id="DataGrid1" runat="server" OnSortCommand="SortGrid"
BorderStyle="None" BorderWidth="1px" BorderColor="#CCCCCC"
BackColor="White" CellPadding="5" AllowSorting="True">
<HeaderStyle Font-Bold="True" ForeColor="White" BackColor="#006699">
</HeaderStyle>
</asp:datagrid>
</P>
</form>
</body>
</HTML>
<script runat="server">
// SortField-Eigenschaft wird in ViewState verfolgt
string SortField {
get {
object o = ViewState["SortField"];
if (o == null) {
return String.Empty;
}
return (string)o;
}
set {
if (value == SortField) {
// Wie in aktueller Sortierdatei, Sortierreihenfolge umkehren
SortAscending = !SortAscending;
}
ViewState["SortField"] = value;
}
}
// SortAscending-Eigenschaft wird in ViewState verfolgt
bool SortAscending {
get {
object o = ViewState["SortAscending"];
if (o == null) {
return true;
}
return (bool)o;
}
set {
ViewState["SortAscending"] = value;
}
}
void Page_Load(object sender, EventArgs e) {
if (!Page.IsPostBack) {
BindGrid();
}
}
void BindGrid() {
// Daten abrufen
DataSet ds = new DataSet();
ds.ReadXml(Server.MapPath("TestData.xml"));
DataView dv = new DataView(ds.Tables[0]);
// Sortierfilter und -richtung anwenden
dv.Sort = SortField;
if (!SortAscending) {
dv.Sort += " DESC";
}
// Raster binden
DataGrid1.DataSource = dv;
DataGrid1.DataBind();
}
void SortGrid(object sender, DataGridSortCommandEventArgs e) {
DataGrid1.CurrentPageIndex = 0;
SortField = e.SortExpression;
BindGrid();
}
</script>
Nachfolgend sehen Sie den Code für: testdata.xml, auf den in beiden Codeabschnitten oben verwiesen wird:
<?xml version="1.0" standalone="yes"?>
<NewDataSet>
<Table>
<pub_id>0736</pub_id>
<pub_name>New Moon Books</pub_name>
<city>Boston</city>
<state>MA</state>
<country>USA</country>
</Table>
<Table>
<pub_id>0877</pub_id>
<pub_name>Binnet & Hardley</pub_name>
<city>Washington</city>
<state>DC</state>
<country>USA</country>
</Table>
<Table>
<pub_id>1389</pub_id>
<pub_name>Algodata Infosystems</pub_name>
<city>Berkeley</city>
<state>CA</state>
<country>USA</country>
</Table>
<Table>
<pub_id>1622</pub_id>
<pub_name>Five Lakes Publishing</pub_name>
<city>Chicago</city>
<state>IL</state>
<country>USA</country>
</Table>
<Table>
<pub_id>1756</pub_id>
<pub_name>Ramona Publishers</pub_name>
<city>Dallas</city>
<state>TX</state>
<country>USA</country>
</Table>
<Table>
<pub_id>9901</pub_id>
<pub_name>GGG&G</pub_name>
<city>München</city>
<country>Germany</country>
</Table>
<Table>
<pub_id>9952</pub_id>
<pub_name>Scootney Books</pub_name>
<city>New York</city>
<state>NY</state>
<country>USA</country>
</Table>
<Table>
<pub_id>9999</pub_id>
<pub_name>Lucerne Publishing</pub_name>
<city>Paris</city>
<country>France</country>
</Table>
</NewDataSet>
Sitzungsstatus oder ViewState?
In bestimmten Fällen ist es nicht die beste Lösung, einen Statuswert in ViewState zu speichern. Die am weitesten verbreitete Alternative ist der Sitzungsstatus. Er eignet sich im Allgemeinen besser für folgende Fälle:
-
Große Datenmengen. Da ViewState die Größe sowohl der an den Browser übertragenen Seite (die HTML-Nutzlast) als auch die Größe des zurückübertragenen Formulars erhöht, ist ViewState eine ungünstige Wahl für das Speichern größerer Datenmengen.
-
Vertrauliche Daten, die noch nicht in der Benutzeroberfläche angezeigt werden. Während die ViewState-Daten codiert und ggf. verschlüsselt werden, sind Ihre Daten am sichersten, solange sie nicht an den Client gesendet werden. Daher ist der Sitzungsstatus eine sicherere Lösung. (Das Speichern von Daten in der Datenbank ist aufgrund von zusätzlichen Datenbankauthentifizierungen sogar noch sicherer. Sie können SSL für eine höhere Hyperlinksicherheit implementieren.) Wenn Sie jedoch bereits private Daten in der Benutzeroberfläche angezeigt haben, reicht Ihnen die Sicherheit des Hyperlinks wahrscheinlich aus. In diesem Fall ist es nicht weniger sicher, dieselben Werte auch in ViewState zu speichern.
-
Objekte, die nicht ohne weiteres in ViewState serialisiert werden (z.B. DataSet). Das ViewState-Serialisierungsprogramm wurde für die kleine Gruppe der unten aufgelisteten allgemeinen Objekttypen optimiert. Weitere serialisierbare Objekttypen können in ViewState beibehalten werden, sind aber langsamer und benötigen sehr viel ViewState-Speicherplatz.
|
| Sitzungsstatus | ViewState |
| Hat Serverressourcen? | Ja | Nein |
| Verursacht Timeout? | Ja - nach 20 Minuten (Standard) | Nein |
| Speichert .NET-Typen? | Ja | Nein, eingeschränkte Unterstützung von: Zeichenfolgen, Ganzzahlen, Booleschen Werten, Arrays, ArrayLists, Hashtables, benutzerdefinierten TypeConverters |
| Erhöht die "HTML-Nutzlast"? | Nein | Ja |
Optimale Leistung mit ViewState
Jedes Objekt muss vor dem Speichern in ViewState serialisiert und beim Zurückübertragen entserialisiert werden, so dass es bei der Verwendung von ViewState zu Leistungseinbußen kommt. Normalerweise entstehen jedoch keine signifikanten Leistungseinbußen, wenn Sie einige einfache Richtlinien beachten, mit denen Sie Ihre ViewState-Kosten unter Kontrolle halten können.
-
Deaktivieren Sie ViewState, wenn es nicht benötigt wird. Im nächsten Abschnitt, Weniger Nutzen von ViewState, wird dies näher erläutert.
-
Verwenden Sie optimierte ViewState-Serialisierungsprogramme. Die oben genannten Typen verfügen über spezielle, sehr schnelle Serialisierungsprogramme, die für eine geringe ViewState-Speicherplatzbelegung optimiert sind. Wenn Sie einen nicht aufgeführten Typ serialisieren möchten, können Sie dessen Leistung durch Erstellen eines benutzerdefinierten TypeConverter verbessern.
-
Verwenden Sie möglichst wenig Objekte und, falls möglich, speichern Sie möglichst wenig Objekte in ViewState. Verwenden Sie anstelle eines zweidimensionalen Zeichenfolgearrays bestehend aus Namen/Werten (dessen Objektanzahl der Arraylänge entspricht) vorzugsweise zwei Zeichenfolgearrays (nur zwei Objekte). Normalerweise jedoch kann durch das Umwandeln zweier bekannter Typen vor dem Speichern in ViewState keine Leistungsverbesserung erzielt werden - Sie bezahlen dann i.d.R. den Umwandlungspreis doppelt.
Weniger Nutzen von ViewState
ViewState wird standardmäßig aktiviert. Die einzelnen Steuerelemente - und nicht der Seitenentwickler - entscheiden, welche Daten in ViewState gespeichert werden. In manchen Fällen sind diese Informationen für Ihre Anwendung nicht von Nutzen. Obwohl nicht nachteilig, können sie jedoch die Größe der an den Browser gesendeten Seiten beträchtlich anwachsen lassen. Daher sollten Sie ViewState deaktivieren, wenn Sie es nicht benötigen, und zwar insbesondere in den Fällen, in denen die ViewState-Größe sehr umfangreich ist.
Sie können ViewState für einzelne Steuerelemente, Seiten oder sogar Anwendungen deaktivieren. Sie benötigen ViewState nicht, wenn die folgenden Voraussetzungen erfüllt sind:
| Seiten | Steuerelemente |
|
|
Das DataGrid-Steuerelement nutzt ViewState besonders intensiv. Alle im Raster angezeigten Daten werden standardmäßig auch in ViewState gespeichert, was eine großartige Sache ist, wenn ein aufwändiger Vorgang (wie eine komplexe Suche) für den Zugriff auf Daten erforderlich ist. Dieses Verhalten macht DataGrid aber auch zu einem Kandidaten für eine unnötige ViewState-Verwendung.
Als Beispiel sei hier eine einfache Webseite gezeigt, die die oben genannten Kriterien erfüllt. ViewState wird nicht benötigt, da die Seite nicht zurückübertragen wird.
Abbildung 3. Einfache Seite "LessViewState.aspx" mit DataGrid1
<%@ Import Namespace="System.Data" %>
<html>
<body>
<form runat="server">
<asp:DataGrid runat="server" />
</form>
</body>
</html>
<script runat="server">
Private Sub Page_Load(sender As Object, e As EventArgs)
Dim ds as New DataSet()
ds.ReadXml(Server.MapPath("TestData.xml"))
DataGrid1.DataSource = ds
DataGrid1.DataBind()
End Sub
</script>
Wenn ViewState aktiviert ist, trägt dieses kleine Raster mit über 3000 Byte zur HTML-Nutzlast der Seite bei! Sie können dies mit der ASP.NET-Ablaufverfolgung oder über den Quellcode der Seite anzeigen, die über den Browser gesendet wurde. Dies finden Sie auch im Code unten dargestellt.
<HTML>
<HEAD>
<title>Reduzieren der Seite "HTML-Nutzlast"</title>
</HEAD>
<body>
<form name="_ctl0" method="post" action="lessviewstate.aspx" id="_ctl0">
<input type="hidden" name="__VIEWSTATE"
value="dDwxNTgzOTU2ODA7dDw7bDxpPDE+Oz47bDx0PDtsPGk8MT47PjtsPHQ8QDA8cDxw
PGw8UGFnZUNvdW50O18hSXRlbUNvdW50O18hRGF0YVNvdXJjZUl0ZW1Db3VudDtEYXRhS2V
5czs+O2w8aTwxPjtpPDg+O2k8OD47bDw+Oz4+Oz47Ozs7Ozs7OztAMDxAMDxwPGw8SGVhZG
VyVGV4dDtEYXRhRmllbGQ7U29ydEV4cHJlc3Npb247UmVhZE9ubHk7PjtsPHB1Yl9pZDtwd
WJfaWQ7cHViX2lkO288Zj47Pj47Ozs7PjtAMDxwPGw8SGVhZGVyVGV4dDtEYXRhRmllbGQ7
U29ydEV4cHJlc3Npb247UmVhZE9ubHk7PjtsPHB1Yl9uYW1lO3B1Yl9uYW1lO3B1Yl9uYW1
lO288Zj47Pj47Ozs7PjtAMDxwPGw8SGVhZGVyVGV4dDtEYXRhRmllbGQ7U29ydEV4cHJlc3
Npb247UmVhZE9ubHk7PjtsPGNpdHk7Y2l0eTtjaXR5O288Zj47Pj47Ozs7PjtAMDxwPGw8S
GVhZGVyVGV4dDtEYXRhRmllbGQ7U29ydEV4cHJlc3Npb247UmVhZE9ubHk7PjtsPHN0YXRl
O3N0YXRlO3N0YXRlO288Zj47Pj47Ozs7PjtAMDxwPGw8SGVhZGVyVGV4dDtEYXRhRmllbGQ
7U29ydEV4cHJlc3Npb247UmVhZE9ubHk7PjtsPGNvdW50cnk7Y291bnRyeTtjb3VudHJ5O2
88Zj47Pj47Ozs7Pjs+Oz47bDxpPDA+Oz47bDx0PDtsPGk8MT47aTwyPjtpPDM+O2k8ND47a
Tw1PjtpPDY+O2k8Nz47aTw4Pjs+O2w8dDw7bDxpPDA+O2k8MT47aTwyPjtpPDM+O2k8ND47
PjtsPHQ8cDxwPGw8VGV4dDs+O2w8MDczNjs+Pjs+Ozs+O3Q8cDxwPGw8VGV4dDs+O2w8TmV
3IE1vb24gQm9va3M7Pj47Pjs7Pjt0PHA8cDxsPFRleHQ7PjtsPEJvc3Rvbjs+Pjs+Ozs+O3
Q8cDxwPGw8VGV4dDs+O2w8TUE7Pj47Pjs7Pjt0PHA8cDxsPFRleHQ7PjtsPFVTQTs+Pjs+O
zs+Oz4+O3Q8O2w8aTwwPjtpPDE+O2k8Mj47aTwzPjtpPDQ+Oz47bDx0PHA8cDxsPFRleHQ7
PjtsPDA4Nzc7Pj47Pjs7Pjt0PHA8cDxsPFRleHQ7PjtsPEJpbm5ldCAmIEhhcmRsZXk7Pj4
7Pjs7Pjt0PH_u56 ?cDxsPFRleHQ7PjtsPFdhc2hpbmd0b247Pj47Pjs7Pjt0PHA8cDxsPFRleHQ7PjtsPERDOz
4+Oz47Oz47dDxwPHA8bDxUZXh0Oz47bDxVU0E7Pj47Pjs7Pjs+Pjt0PDtsPGk8MD47aTwxP
jtpPDI+O2k8Mz47aTw0Pjs+O2w8dDxwPHA8bDxUZXh0Oz47bDwxMzg5Oz4+Oz47Oz47dDxw
PHA8bDxUZXh0Oz47bDxBbGdvZGF0YSBJbmZvc3lzdGVtczs+Pjs+Ozs+O3Q8cDxwPGw8VGV
4dDs+O2w8QmVya2VsZXk7Pj47Pjs7Pjt0PHA8cDxsPFRleHQ7PjtsPENBOz4+Oz47Oz47dD
xwPHA8bDxUZXh0Oz47bDxVU0E7Pj47Pjs7Pjs+Pjt0PDtsPGk8MD47aTwxPjtpPDI+O2k8M
z47aTw0Pjs+O2w8dDxwPHA8bDxUZXh0Oz47bDwxNjIyOz4+Oz47Oz47dDxwPHA8bDxUZXh0
Oz47bDxGaXZlIExha2VzIFB1Ymxpc2hpbmc7Pj47Pjs7Pjt0PHA8cDxsPFRleHQ7PjtsPEN
oaWNhZ287Pj47Pjs7Pjt0PHA8cDxsPFRleHQ7PjtsPElMOz4+Oz47Oz47dDxwPHA8bDxUZX
h0Oz47bDxVU0E7Pj47Pjs7Pjs+Pjt0PDtsPGk8MD47aTwxPjtpPDI+O2k8Mz47aTw0Pjs+O
2w8dDxwPHA8bDxUZXh0Oz47bDwxNzU2Oz4+Oz47Oz47dDxwPHA8bDxUZXh0Oz47bDxSYW1v
bmEgUHVibGlzaGVyczs+Pjs+Ozs+O3Q8cDxwPGw8VGV4dDs+O2w8RGFsbGFzOz4+Oz47Oz4
7dDxwPHA8bDxUZXh0Oz47bDxUWDs+Pjs+Ozs+O3Q8cDxwPGw8VGV4dDs+O2w8VVNBOz4+Oz
47Oz47Pj47dDw7bDxpPDA+O2k8MT47aTwyPjtpPDM+O2k8ND47PjtsPHQ8cDxwPGw8VGV4d
Ds+O2w8OTkwMTs+Pjs+Ozs+O3Q8cDxwPGw8VGV4dDs+O2w8R0dHJkc7Pj47Pjs7Pjt0PHA8
cDxsPFRleHQ7PjtsPE3DvG5jaGVuOz4+Oz47Oz47dDxwPHA8bDxUZXh0Oz47bDwmbmJzcFw
7Oz4+Oz47Oz47dDxwPHA8bDxUZXh0Oz47bDxHZXJtYW55Oz4+Oz47Oz47Pj47dDw7bDxpPD
A+O2k8MT47aTwyPjtpPDM+O2k8ND47PjtsPHQ8cDxwPGw8VGV4dDs+O2w8OTk1Mjs+Pjs+O
zs+O3Q8cDxwPGw8VGV4dDs+O2w8U2Nvb3RuZXkgQm9va3M7Pj47Pjs7Pjt0PHA8cDxsPFRl
eHQ7PjtsPE5ldyBZb3JrOz4+Oz47Oz47dDxwPHA8bDxUZXh0Oz47bDxOWTs+Pjs+Ozs+O3Q
8cDxwPGw8VGV4dDs+O2w8VVNBOz4+Oz47Oz47Pj47dDw7bDxpPDA+O2k8MT47aTwyPjtpPD
M+O2k8ND47PjtsPHQ8cDxwPGw8VGV4dDs+O2w8OTk5OTs+Pjs+Ozs+O3Q8cDxwPGw8VGV4d
Ds+O2w8THVjZXJuZSBQdWJsaXNoaW5nOz4+Oz47Oz47dDxwPHA8bDxUZXh0Oz47bDxQYXJp
czs+Pjs+Ozs+O3Q8cDxwPGw8VGV4dDs+O2w8Jm5ic3BcOzs+Pjs+Ozs+O3Q8cDxwPGw8VGV
4dDs+O2w8RnJhbmNlOz4+Oz47Oz47Pj47Pj47Pj47Pj47Pj47Pg==" />
Bingo! Durch einfaches Deaktivieren von ViewState für das Raster wird die Nutzlastgröße für dieselbe Seite drastisch reduziert:
<HTML>
<HEAD>
<title>Reduzieren der Seite "HTML-Nutzlast"</title>
</HEAD>
<body>
<form name="_ctl0" method="post" action="lessviewstate.aspx" id="_ctl0">
<input type="hidden" name="__VIEWSTATE" value="dDwxNTgzOTU2ODA7Oz4=" />
Nachfolgend sehen Sie den vollständigen LessViewState-Code in Visual Basic und C#:
[Visual Basic]
<%@ Import Namespace="System.Data" %>
<html>
<HEAD>
<title>Reduzieren der Seite "HTML-Nutzlast"</title>
</HEAD>
<body>
<form runat="server">
<H3>
Reduzieren der Seite "HTML-Nutzlast" durch Deaktivieren von ViewState
</H3>
<P>
<asp:datagrid id="DataGrid1" runat="server" EnableViewState="false"
BorderStyle="None" BorderWidth="1px" BorderColor="#CCCCCC"
BackColor="White" CellPadding="5">
<HeaderStyle Font-Bold="True" ForeColor="White" BackColor="#006699">
</HeaderStyle>
</asp:datagrid>
</P>
</form>
</body>
</html><script runat="server">
Private Sub Page_Load(sender As Object, e As EventArgs)
Dim ds as New DataSet()
ds.ReadXml(Server.MapPath("TestData.xml"))
DataGrid1.DataSource = ds
DataGrid1.DataBind()
End Sub
</script>
[C#]
<%@ Page Language="C#" %>
<%@ Import Namespace="System.Data" %>
<html>
<HEAD>
<title>Reduzieren der Seite "HTML-Nutzlast"</title>
</HEAD>
<body>
<form runat="server">
<H3>
Reduzieren der Seite "HTML-Nutzlast" durch Deaktivieren von ViewState
</H3>
<P>
<asp:datagrid id="DataGrid1" runat="server" EnableViewState="false"
BorderStyle="None" BorderWidth="1px" BorderColor="#CCCCCC"
BackColor="White" CellPadding="5">
<HeaderStyle Font-Bold="True" ForeColor="White" BackColor="#006699">
</HeaderStyle>
</asp:datagrid>
</P>
</form>
</body>
</html>
<script runat="server">
void Page_Load(object sender, EventArgs e) {
DataSet ds = new DataSet();
ds.ReadXml(Server.MapPath("TestData.xml"));
DataGrid1.DataSource = ds;
DataGrid1.DataBind();
}
</script>
Deaktivieren von ViewState
Im obigen Beispiel erfolgte die Deaktivierung von ViewState für das Raster, indem ich die EnableViewState-Rastereigenschaft auf False gesetzt habe. ViewState kann für ein einzelnes Steuerelement, eine ganze Seite oder sogar eine komplette Anwendung wie folgt deaktiviert werden:
| Pro Steuerelement (in Tag) | <asp:datagrid EnableViewState="false" . /> |
| Pro Seite (in Direktive) | <%@ Page EnableViewState="False" . %> |
| Pro Anwendung (in der Datei "web.config") | <Pages EnableViewState="false" . /> |
Mehr Sicherheit für ViewState
Da ViewState nicht als Klartext formatiert ist, meinen einige Benutzer, ViewState sei verschlüsselt - was es aber nicht ist. ViewState ist nur base64-verschlüsselt, um sicherzustellen, dass Werte nicht während des Roundtrips verändert werden, ungeachtet davon, ob die Anwendung eine Antwort/Abfrage-Verschlüsselung verwendet.
Sie können Ihrer Anwendung zwei Stufen der ViewState-Sicherheit hinzufügen:
-
Manipulationsprüfung
-
Verschlüsselung
Beachten Sie, dass die ViewState-Sicherheit direkte Auswirkungen auf die erforderliche Zeit für das Bearbeiten und Rendern einer ASP.NET-Seite hat. Mehr Sicherheit bedeutet mehr Rechnerzeit. Fügen Sie deshalb ViewState nicht mehr Sicherheit hinzu, wenn Sie sie gar nicht benötigen.
Manipulationsprüfung
Hashcode sichert nicht die eigentlichen Daten im ViewState-Feld, reduziert aber in erheblichem Umfang die Wahrscheinlichkeit, dass eine Person ViewState manipuliert, um Ihre Anwendung zu spoofen bzw. zu imitieren, d.h. Werte zurückzuübertragen, deren Eingabe durch die Anwendung normalerweise verhindert würde.
Sie können ASP.NET anweisen, einen Hashcode an das ViewState-Feld anzuhängen, indem Sie das EnableViewStateMAC-Attribut setzen:
<%@Page EnableViewStateMAC=true %>
EnableViewStateMAC kann auf Seiten- oder Anwendungsebene gesetzt werden. Bei der Rückübertragung erzeugt ASP.NET einen Hashcode für die ViewState-Daten und vergleicht diese mit dem Hashcode im bereitgestellten Wert. Stimmen sie nicht überein, werden die ViewState-Daten verworfen, und die Steuerelemente werden auf die ursprünglichen Einstellungen zurückgesetzt.
ASP.NET erzeugt standardmäßig den ViewState-Hashcode unter Verwendung des SHA1-Algorithmus. Sie können auch den MD5-Algorithmus wählen, indem Sie <machineKey> in der Datei machine.config wie folgt setzen:
<machineKey validation="MD5" />
Verschlüsselung
Durch Verschlüsselung können Sie die eigentlichen Datenwerte im ViewState-Feld schützen. Setzen Sie zunächst
EnableViewStatMAC="true"
, wie oben gezeigt. Setzen Sie dann den Validation-Typ für machineKey auf 3DES. Damit wird ASP.NET angewiesen, den ViewState-Wert mittels des symmetrischen Dreifach-DES-Verschlüsselungsalgorithmus zu verschlüsseln.
<machineKey validation="3DES" />
"ViewState"-Sicherheit in einer Webfarm
ASP.NET erzeugt standardmäßig einen Validierungsschlüssel nach dem Zufallsprinzip und speichert diesen in allen Server-LSAs (Local Security Authority). Wenn Sie ein ViewState-Feld validieren möchten, das auf einem anderen Server erstellt wurde, muss der validationKey für beide Server auf denselben Wert gesetzt sein. Wenn Sie ViewState Sicherheit durch eines der oben genannten Verfahren hinzufügen, um eine Anwendung in einer Webfarmkonfiguration zu schützen, müssen Sie einen einzigen, gemeinsam verwendeten Schlüssel für alle Server bereitstellen.
Der Validierungsschlüssel ist eine Zeichenfolge aus 20 bis 64 zufälligen, kryptografisch starken Bytes, die als 40 bis 128 hexadezimale Zeichen dargestellt werden. Je länger, desto sicherer. Ich empfehle daher einen Schlüssel aus 128 Zeichen für Computer, die einen solchen Schlüssel unterstützen. z.B.:
<machineKey validation="SHA1" validationKey=" F3690E7A3143C185AB1089616A8B4D81FD55DD7A69EEAA3B32A6AE813ECEECD28DEA66A 23BEE42193729BD48595EBAFE2C2E765BE77E006330BC3B1392D7C73F" />
Der System.Security.Cryptography-Namespace enthält die RNGCryptoServiceProvider-Klasse, die Sie zur Erzeugung dieser Zeichenfolge verwenden können, wie es das folgende GenerateCryptoKey.aspx-Beispiel zeigt:
<%@ Page Language="c#" %>
<%@ Import Namespace="System.Security.Cryptography" %>
<HTML>
<body>
<form runat="server">
<H3>Zufälligen Verschlüsselungsschlüssel erzeugen</H3>
<P>
<asp:RadioButtonList id="RadioButtonList1"
runat="server" RepeatDirection="Horizontal">
<asp:ListItem Value="40">40-byte</asp:ListItem>
<asp:ListItem Value="128" Selected="True">128-byte</asp:ListItem>
</asp:RadioButtonList>
<asp:Button id="Button1" runat="server" onclick="GenerateKey"
Text="Schlüssel erzeugen">
</asp:Button></P>
<P>
<asp:TextBox id="TextBox1" runat="server" TextMode="MultiLine"
Rows="10" Columns="70" BackColor="#EEEEEE" EnableViewState="False">
Erzeugte Ergebnisse kopieren und einfügen</asp:TextBox></P>
</form>
</body>
</HTML>
<script runat=server>
void GenerateKey(object sender, System.EventArgs e)
{
int keylength = Int32.Parse(RadioButtonList1.SelectedItem.Value);
// Hier Benutzercode einfügen, um Seite zu initialisieren
byte[] buff = new Byte[keylength/2];
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
// Array ist nicht mit kryptografisch starken, zufälligen Bytes gefüllt
rng.GetBytes(buff);
StringBuilder sb = new StringBuilder(keylength);
int i;
for (i = 0; i < buff.Length; i++) {
sb.Append(String.Format("{0:X2}",buff[i]));
}
// In Textfeld einfügen, damit der Benutzer sie kopieren kann
TextBox1.Text = sb.ToString();
}
</script>
Zusammenfassung
ASP.NET ViewState ist eine neue Art von Statusdienst für Entwickler, um den Benutzeroberflächenstatus auf Benutzerbasis verfolgen zu können. Dies geschieht ganz ohne Zauberei. Es bedarf nur eines altbekannten Webprogrammiertricks - Statusroundtrips in einem verborgenen Formularfeld - und schon wird das Ganze direkt in das Seitenverarbeitungsframework integriert. Das Ergebnis hingegen ist sehr ansehnlich - sehr viel weniger Code in webbasierten Formularen, der geschrieben und gepflegt werden muss.
Sie werden ViewState nicht immer einsetzen müssen, aber wenn Sie es verwenden, ist es eines der herausragendsten Features, die ASP.NET für Webseitenentwickler bereithält.

Nothin' But ASP.NET: Taking a Bite Out of ASP.NET ViewState