I have lots of experience with C#, but I am fairly new to Web Forms.
I am working on a project where a lot of data is stored in the ViewState and I don't understand why.
My understanding is that the object representing my Page (System.Web.UI.Page) is persistent for the life of that Page. There may be some behind-the-scenes magic where an identifier is stored in ViewState, but when reacting to events on that page, can I not simply refer to "this" and its properties/methods?
When would I explicitly store data in the ViewState as opposed to simply using the properties of the current object (Page in this case)?
My understanding is that the object representing my Page (System.Web.UI.Page) is persistent for the life of that Page
This is correct, however the lifetime of the page is only for a single request, after the HTML has been delivered to the client then the Page
instance is destroyed.
I recommend reading this article: https://msdn.microsoft.com/en-us/library/ms178472.aspx
Note that WebForms' design: an abstraction of the stateless-web into a pseudo-stateful WinForms-like environment is largely considered a mistake and that's why ASP.NET MVC and ASP.NET Core has a radically different design (though Controller
instances can be compared to Page
instances, with similar lifecycle semantics but considerably less overhead).
There may be some behind-the-scenes magic where an identifier is stored in ViewState, but when reacting to events on that page, can I not simply refer to "this" and its properties/methods?
I'm having difficulty understanding this - but if you think that all instance members of a Page
, including custom properties using only a backing field are automatically persisted between requests (including "postback" requests) then no, that is not true. There is no magic persistence for fields, you need to use the Page.ViewState
property as a backing-store for those properties, and that data is only persisted between special "postback" POST requests.
Let me try my own explanation:
GET /MyForm.aspx
MyForm : System.Web.UI.Page
, creates all child-control instances declared in the .aspx
file, and calls the Init
and Load
events on all the Controls, then Render
to generate output HTML, then Unload
. The MyForm
instance for the request is then garbage-collected.If MyForm.aspx
contains a <form runat="server">
and makes use of "postback", then when the user does something that triggers a postback then:
POST /MyForm.aspx
where the request body is the data from the <input >
elements. Under the rules of HTML, only the contents of <input>
(and <select>
, <textarea>
, etc) are submitted in the POST request and not the entire DOM - this is a problem for ASP.NET WebForms because all those Controls
have many properties and settings (e.g. <asp:Label FontColor="">
which are not persisted through their own <input type="hidden" name="label123_FontColor">
, besides, even if they were that's a lot of verbose data to send back to the server.So instead, ASP.NET instructs all the Control
instances to serialize all their non-<input>
data to the ViewState
dictionary (which represents the state of the View (in MVP/MVC parlance, the .aspx
/HTML is the View - hence persisting its state separate from the Request state which by-definition is short-lived).
In a Control
or Page
subclass you need to use ViewState, not a backing field:
public String SomeName {
get { return this.ViewState["SomeName"] as String; }
set { this.ViewState["SomeName"] = value; }
}
...and then ViewState
is serialized and compressed and signed and rendered to the page in <input name="__VIEWSTATE" type="hidden">
).
The reason state is carried in __VIEWSTATE
instead of simply regenerating the entire page's data on every page request is because sometimes generating the page initially can involve heavy lifting (e.g. a DB query). The argument is that if you have a page with a list of data and the user is simply manipulating that data before saving it back to the DB then you shouldn't need to reload from the DB and instead store that view-level data in the page's __VIEWSTATE
as though it's some kind of super-cookie or something.