Ein mundgerechtes Stück ASP.NET ViewState

Veröffentlicht: 04. Feb 2002 | Aktualisiert: 14. Jun 2004
Von Susan Warren

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 Antwort: ViewState behält den Status der Benutzeroberfläche einer Webseite bei
Größerer Nutzen von ViewState Größerer Nutzen von ViewState
Weniger Nutzen von ViewState Weniger Nutzen von ViewState
Mehr Sicherheit für ViewState Mehr Sicherheit für ViewState
Zusammenfassung 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.

Bild01

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.

Bild02

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.

  1. 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.

  2. 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.

  3. 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 &amp; 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&amp;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

  • Keine Rückübertragung der Seite.
  • Sie behandeln die Steuerelementereignisse nicht.
  • Das Steuerelement verfügt über keine dynamischen oder datengebundenen Eigenschaftswerte (bzw. sie werden im Code bei jeder Anfrage festgelegt).

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.

Bild03

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>&nbsp; 
            <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.


Anzeigen: