分享
 
 
 

Taking a Bite Out of ASP.NET ViewState

王朝vc·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

Taking a Bite Out of ASP.NET ViewState

Susan Warren

Microsoft Corporation

November 27, 2001

When I meet and talk to new ASP.NET page developers, one of the first things they usually ask me is, "What is that ViewState thing, anyway?" And often you can hear in their voices that same queasy fascination I feel when a waiter in some exotic restaurant parks a plateful of some previously unknown food in front of me. Somebody must think it's good; otherwise, they wouldn't be serving it. So, I'll try it, and maybe even love it, but it sure looks odd!

It's that way with ViewState too. Once you get past how it looks, you'll find many circumstances where you'll be delighted to have ViewState in your ASP.NET application, because it lets you do much more with much less code. But there will also be times when you'll want to definitely leave ViewState on the plate. We'll look at both scenarios, but first, let's answer that question about what is ViewState.

Answer: ViewState Maintains the UI State of a Page

The Web is stateless, and so are ASP.NET Pages. They are instantiated, executed, rendered, and disposed on every round trip to the server. As a Web developer, you can add statefulness using well-known techniques like storing state on the server in Session state or by posting a page back to itself. Take the sign up form in Figure 1 as an example.

Figure 1. Restoring posted form values

You can see I've picked an invalid value for my potluck item. Like most forms on the Web, this one is friendly enough to put a helpful error message and a star next to the field in error. In addition, all of the valid values I entered in the other text boxes and drop-down lists still appear in the form. This is possible, in part, because HTML form elements post their current values from the browser to the server in the HTTP header. You can use ASP.NET tracing to see the form values that are posted back, as in Figure 2.

Figure 2. Values posted in HTTP Form, as shown by ASP.NET trace

Before ASP.NET, restoring the values back into the form fields across multiple postbacks was entirely the responsibility of the page developer, who had to pick them out, one-by-one, from the HTTP form, and push them back into the fields. Happily, ASP.NET does this trick automatically, thus eliminating both a lot of grunt work and a lot of code for forms. But that's not ViewState.

ViewState is the mechanism ASP.NET uses to keep track of server control state values that don't otherwise post back as part of the HTTP form. For example, the text shown by a Label control is saved in ViewState by default. As a developer, you can bind data or programmatically set the Label just once when the page first loads, and on subsequent postbacks, the label text will be repopulated automatically from ViewState. So in addition to less grunt work and less code, the benefit of ViewState is often fewer trips to the database.

How ViewState Works

There's really nothing magical about ViewState. It's a hidden form field managed by the ASP.NET page framework. When ASP.NET executes a page, the ViewState values from the page and all of the controls are collected and formatted into a single encoded string, and then assigned to the value attribute of the hidden form field (specifically, <input type=hidden>). Since the hidden form field is part of the page sent to the client, the ViewState value is temporarily stored in the client's browser. If the client chooses to post the page back to the server, the ViewState string is posted back too. You can actually see the ViewState form field and its postback value in Figure 2 above.

Upon postback, the ASP.NET page framework parses the ViewState string and populates the ViewState properties for the page and each of the controls. The controls, in turn, use the ViewState data to rehydrate themselves to their former state.

There are three more small, but useful things to know about ViewState.

You must have a server-side form tag (<form runat=server>) in your ASPX page if you want to use ViewState. A form field is required so the hidden field that contains the ViewState information can post back to the server. And, it must be a server-side form so the ASP.NET page framework can add the hidden field when the page is executed on the server.

The page itself saves 20 or so bytes of information into ViewState, which it uses to distribute PostBack data and ViewState values to the correct controls upon postback. So, even if ViewState is disabled for the page or application, you may see a few remaining bytes in ViewState.

In cases where the page does not post back, you can eliminate ViewState from a page by omitting the server side <form> tag.

Getting More from ViewState

ViewState is a marvelous way to track the state of a control across postbacks since it doesn't use server resources, doesn't time out, and works with any browser. If you are a control author, you'll definitely want to check out Maintaining State in a Control.

Page authors can also benefit from ViewState in much the same way. Occasionally your pages will contain UI state values that aren't stored by a control. You can track values in ViewState using a programming syntax is similar to that for Session and Cache:

[Visual Basic]' save in ViewState

ViewState("SortOrder") = "DESC"

' read from ViewState

Dim SortOrder As String = CStr(ViewState("SortOrder"))

[C#]// save in ViewState

ViewState["SortOrder"] = "DESC";

// read from ViewState

string sortOrder = (string)ViewState["SortOrder"];

Consider this example: you want to display a list of items in a Web page, and each user wants to sort the list differently. The list of items is static, so the pages can each bind to the same cached set of data, but the sort order is a small bit of user-specific UI state. ViewState is a great place to store this type of value. Here's the code:

[Visual Basic]<%@ Import Namespace="System.Data" %>

<HTML>

<HEAD>

<title>ViewState for Page UI State Values</title>

</HEAD>

<body>

<form runat="server">

<H3>

Storing Non-Control State in ViewState

</H3>

<P>

This example stores the current sort order for a static

list of data in ViewState.<br>

Click the link in the column header to sort the data by that field.<br>

Click the link a second time to reverse the sort direction.

<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 property is tracked in ViewState

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

' same as current sort file, toggle sort direction

SortAscending = Not SortAscending

End If

ViewState("SortField") = Value

End Set

End Property

' SortAscending property is tracked in ViewState

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()

' Get data

Dim ds As New DataSet()

ds.ReadXml(Server.MapPath("TestData.xml"))

Dim dv As New DataView(ds.Tables(0))

' Apply sort filter and direction

dv.Sort = SortField

If Not SortAscending Then

dv.Sort += " DESC"

End If

' Bind grid

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 for Page UI State Values</title>

</HEAD>

<body>

<form runat="server">

<H3>

Storing Non-Control State in ViewState

</H3>

<P>

This example stores the current sort order for a static

list of data in ViewState.<br>

Click the link in the column header to sort the data by that field.<br>

Click the link a second time to reverse the sort direction.

<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 property is tracked in ViewState

string SortField {

get {

object o = ViewState["SortField"];

if (o == null) {

return String.Empty;

}

return (string)o;

}

set {

if (value == SortField) {

// same as current sort file, toggle sort direction

SortAscending = !SortAscending;

}

ViewState["SortField"] = value;

}

}

// SortAscending property is tracked in ViewState

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() {

// get data

DataSet ds = new DataSet();

ds.ReadXml(Server.MapPath("TestData.xml"));

DataView dv = new DataView(ds.Tables[0]);

// Apply sort filter and direction

dv.Sort = SortField;

if (!SortAscending) {

dv.Sort += " DESC";

}

// Bind grid

DataGrid1.DataSource = dv;

DataGrid1.DataBind();

}

void SortGrid(object sender, DataGridSortCommandEventArgs e) {

DataGrid1.CurrentPageIndex = 0;

SortField = e.SortExpression;

BindGrid();

}

</script>

Here's the code for testdata.xml, referenced in both code sections above:

<?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&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>

Session State or ViewState?

There are certain cases where holding a state value in ViewState is not the best option. The most commonly used alternative is Session state, which is generally better suited for:

Large amounts of data. Since ViewState increases the size of both the page sent to the browser (the HTML payload) and the size of form posted back, it's a poor choice for storing large amounts of data.

Secure data that is not already displayed in the UI. While the ViewState data is encoded and may optionally be encrypted, your data is most secure if it is never sent to the client. So, Session state is a more secure option. (Storing the data in the database is even more secure due to the additional database credentials. You can add SSL for even better link security.) But if you've displayed the private data in the UI, presumably you're already comfortable with the security of the link itself. In this case, it is no less secure to put the same value into ViewState as well.

Objects not readily serialized into ViewState, for example, DataSet. The ViewState serializer is optimized for a small set of common object types, listed below. Other types that are serializable may be persisted in ViewState, but are slower and generate a very large ViewState footprint.

Session State

ViewState

Holds server resources?

Yes

No

Times out?

Yes – after 20 minutes (default)

No

Stores any .NET type?

Yes

No, limited support for: strings, integers, Booleans, arrays, ArrayList, hashtable, custom TypeConverters

Increases "HTML payload"?

No

Yes

Getting the Best Performance with ViewState

Each object must be serialized going into ViewState and then deserialized upon post back, so the performance cost of using ViewState is definitely not free. However, there's usually no significant performance impact if you follow some simple guidelines to keep your ViewState costs under control.

Disable ViewState when you don't need it. The next section, Getting Less from ViewState, covers this in detail.

Use the optimized ViewState serializers. The types listed above have special serializers that are very fast and optimized to produce a small ViewState footprint. When you want to serialize a type not listed above, you can greatly improve its performance by creating a custom TypeConverter for it.

Use the fewest number of objects, and if possible, reduce the number of objects you put into ViewState. For example, rather than a two-dimensional string array of names/values (which has as many objects as the length of the array), use two string arrays (only two objects). However, there is usually no performance benefit to convert between two known types before storing them in ViewState—then you're basically paying the conversion price twice.

Getting Less from ViewState

ViewState is enabled by default, and it's up to each control—not the page developer—to decide what gets stored in ViewState. Sometimes, this information is not useful to your application. While it's not harmful either, it can dramatically increase the size of the page sent to the browser. It's a good idea to turn off ViewState if you are not using it, especially where the ViewState size is significant.

You can turn off ViewState on a per-control, per-page, or even per-application basis. You don't need ViewState if:

Pages

Controls

The page doesn't post back to itself.

You aren't handling the control's events.

The control has no dynamic or data bound property values (or they are set in code on every request).

The DataGrid control is a particularly heavy user of ViewState. By default, all of the data displayed in the grid is also stored in ViewState, and that's a wonderful thing when an expensive operation (like a complex search) is required to fetch the data. However, this behavior also makes DataGrid the prime suspect for unnecessary ViewState.

For example, here's a simple page that meets the criteria above. ViewState is not needed because the page doesn't post back to itself.

Figure 3. Simple page LessViewState.aspx with 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>

With ViewState enabled, this little grid contributes over 3000 bytes to the HTML payload for the page! You can see this using ASP.NET Tracing, or by viewing the source of the page sent to the browser, as shown in the code below.

<HTML>

<HEAD>

<title>Reducing Page "HTML Payload"</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==" />

Yikes! By simply disabling ViewState for the grid, the payload size for the same page becomes dramatically smaller:

<HTML>

<HEAD>

<title>Reducing Page "HTML Payload"</title>

</HEAD>

<body>

<form name="_ctl0" method="post" action="lessviewstate.aspx" id="_ctl0">

<input type="hidden" name="__VIEWSTATE" value="dDwxNTgzOTU2ODA7Oz4=" />

Here's the complete LessViewState code in Visual Basic and C#:

[Visual Basic]<%@ Import Namespace="System.Data" %>

<html>

<HEAD>

<title>Reducing Page "HTML Payload"</title>

</HEAD>

<body>

<form runat="server">

<H3>

Reducing Page "HTML Payload" by Disabling 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>Reducing Page "HTML Payload"</title>

</HEAD>

<body>

<form runat="server">

<H3>

Reducing Page "HTML Payload" by Disabling 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>

Disabling ViewState

In the example above, I disabled ViewState for the grid by setting its EnableViewState property to false. ViewState can be disabled for a single control, for an entire page, or for an entire application, as follows:

Per control (on tag)

<asp:datagrid EnableViewState="false" ... />

Per page (in directive)

<%@ Page EnableViewState="False" ... %>

Per application (in web.config)

<Pages EnableViewState="false" ... />

Making ViewState More Secure

Because it's not formatted as clear text, folks sometimes assume that ViewState is encrypted—it's not. Instead, ViewState is merely base64-encoded to ensure that values are not altered during a roundtrip, regardless of the response/request encoding used by the application.

There are two levels of ViewState security you may wish to add to your application:

Tamper-proofing

Encryption

It's important to note that ViewState security has a direct effect on the time required to process and render an ASP.NET page. In short, more secure is slower, so don't add security to ViewState if you don't need it.

Tamper-Proofing

A hashcode will not secure the actual data within the ViewState field, but it will greatly reduce the likelihood of someone tampering with ViewState to try to spoof your application, that is, posting back values that your application would normally prevent a user from inputting.

You can instruct ASP.NET to append a hashcode to the ViewState field by setting the EnableViewStateMAC attribute:

<%@Page EnableViewStateMAC=true %>

EnableViewStateMAC can be set at the page or application level. Upon postback, ASP.NET will generate a hashcode for the ViewState data and compare it to the hashcode store in the posted value. If they don't match, the ViewState data will be discarded and the controls will revert to their original settings.

By default, ASP.NET generates the ViewState hashcode using the SHA1 algorithm. Alternatively, you can select the MD5 algorithm by setting <machineKey> in the machine.config file as follows:

<machineKey validation="MD5" />

Encryption

You can use encryption to protect the actual data values within the ViewState field. First, you must set EnableViewStatMAC="true", as above. Then, set the machineKey validation type to 3DES. This instructs ASP.NET to encrypt the ViewState value using the Triple DES symmetric encryption algorithm.

<machineKey validation="3DES" />

ViewState Security on a Web Farm

By default, ASP.NET creates a random validation key and stores it in each server's Local Security Authority (LSA). In order to validate a ViewState field created on another server, the validationKey for both servers must be set to the same value. If you secure ViewState by any of the means listed above for an application running in a Web Farm configuration, you will need to provide a single, shared validation key for all of the servers.

The validation key is a string of 20 to 64 random, cryptographically-strong bytes, represented as 40 to 128 hexadecimal characters. Longer is more secure, so a 128-character key is recommended for machines that support it. For example:

<machineKey validation="SHA1" validationKey="

F3690E7A3143C185AB1089616A8B4D81FD55DD7A69EEAA3B32A6AE813ECEECD28DEA66A

23BEE42193729BD48595EBAFE2C2E765BE77E006330BC3B1392D7C73F" />

The System.Security.Cryptography namespace includes the RNGCryptoServiceProvider class that you can use to generate this string, as demonstrated in the following GenerateCryptoKey.aspx sample:

<%@ Page Language="c#" %>

<%@ Import Namespace="System.Security.Cryptography" %>

<HTML>

<body>

<form runat="server">

<H3>Generate Random Crypto Key</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="Generate Key">

</asp:Button></P>

<P>

<asp:TextBox id="TextBox1" runat="server" TextMode="MultiLine"

Rows="10" Columns="70" BackColor="#EEEEEE" EnableViewState="False">

Copy and paste generated results</asp:TextBox></P>

</form>

</body>

</HTML>

<script runat=server>

void GenerateKey(object sender, System.EventArgs e)

{

int keylength = Int32.Parse(RadioButtonList1.SelectedItem.Value);

// Put user code to initialize the page here

byte[] buff = new Byte[keylength/2];

RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();

// The array is now filled with cryptographically strong random bytes

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]));

}

// paste to the textbox to the user can copy it out

TextBox1.Text = sb.ToString();

}

</script>

Summary

ASP.NET ViewState is a new kind of state service that developers can use to track UI state on a per-user basis. There's nothing magical about it. It simply takes an old Web programming trick—roundtripping state in a hidden form field—and bakes it right into the page-processing framework. But the result is pretty wonderful—a lot less code to write and maintain in your Web-based forms.

You won't always need it, but when you do, I think you'll find ViewState is a satisfying addition to the feast of new features ASP.NET offers to page developers.

Susan Warren is a program manager for ASP.NET on the .NET Framework team.

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有