When in the page lifecycle is the ViewState collection available? - asp.net

When exactly is the view state accessible from the .Viewstate property of a control? From my observations, the closest event is on the Page.PreLoad event (at Page.InitComplete, Viewstate is still unavailable).
However, for controls that implement the IPostBackEventHandler interface the LoadValue() method is called and the .Viewstate collection is available (this occurs after Page.InitComplete and before Page.PreLoad).
Does anyone know of any additional events that can be used to know when Viewstate is available? Or any tricks (not excluding reflection on private/protected/internal members) that can be used to know if the Viewstate has loaded or not?

When exactly is the view state accessible from the .Viewstate property of a control?
After the LoadViewState method has been run.
Normally this means after the Init phase and before the Load and Handlers (e.g. "OnClick") phase. But ViewState is really complicated, so I highly recommend reading this excellent article to truly understand ViewState.
Since you can override the LoadViewState method, this makes a good place to put any of the kind of tricks you mention:
protected override void LoadViewState(object savedState)
{
base.LoadViewState(savedState);
this.ViewStateLoaded = true; // or you could fire an event or something
UpdatePanelVisibility();
}
Of course, this does assume that you are using your own implementations of controls, which is not always the case.

Related

Performance-impact of empty Page_Load() methods

When adding a new page or user control to an ASP.NET webforms application, the code-behind class contains an empty Page_Load() event handler:
public partial class Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
}
I have an existing web app, where many pages and controls still contain these empty event handlers (they are not used).
Question: Is there any performance impact due to these empty event handlers and should they therefore be removed from all pages and controls?
Please note: I'm not mainly (or not only) concerned about any runtime-overhead, due to the empty event handler being called. I also wonder about any overhead while the page (markup) is JIT-compiled (because the event handlers have to be wired up to the events - probably using some reflection code).
Update: there was no real answer so far, so I can't accept any of them.
AutoEventWireup is not done at the compile time. When it set to true, the runtime has to look for each of the page event handlers using Delegate.CreateDelegate method for this. Here is a great article which describes this behaviour: Inside AutoEventWireup.
There is a similar question here: What is the performance cost of autoeventwireup?
While the stack frame must be adjusted to enter and leave your method (and doing nothing) as opposed to simply calling the base implementation (in this case System.Web.UI.Page
), the performance impact is incredibly small and most likely unmeasurable so you should be fine.
I'm fairly certain Page_Load occurs whether it's there or not. Much like PreRender occurs, or Page_Init.
Removing it will do nothing for performance.

Failed to load viewstate. The control tree into which viewstate is being loaded must match the control tree that was used to save viewstate

I'm currently working on a dynamic core for several webprojects. It has a core that uses a treeview and a menu. And then for each specific projekt it loads several different wuc into a maincontent. Some business projects use business related wucs while others uses different ones. So the span of wuc's is really big.
Now to my problem, whenever a user press a menuitem or a treeitem it loads a wuc to the maincontent linked to that object.
But I'm having some viewstate errors and i've been looking around for 2 days now and none of the solutions explained are working for my projekt.
All my wuc has to have viewstate enabled.
Cycle is ->
Page(Control A) does postback with variable to change control to ControlB in wucPanel(UpdatePanel).
OnLoad LoadRequested Wuc.
Current code is
protected void Load_Page(object sender, EventArgs e)
{
//Code to decide which wuc to load.
UserControl wucc = (UserControl)Page.LoadControl(sFilePath);
ParentControl.ContentTemplateContainer.Controls.Add(wucc);
}
I've tried several fixes like adding diffrent ids to the wuc, but this either disabels the internal functions of control like handlers etc or generates the same viewstate error.
One solution i found was to load ControlA and then just removing it and then load ControlB. But this disabled the scripts for my 3rd party controller (Telerik).
I've also read about having diffrent PlaceHolders for each typof but since i expect havign up to 50 diffrent Controls I don't feel this is gonna help me.
And moving from Page_Load -> Page_Init generated the same error.
Error:
Failed to load viewstate. The control tree into which viewstate is being loaded must match the control tree that was used to save viewstate during the previous request. For example, when adding controls dynamically, the controls added during a post-back must match the type and position of the controls added during the initial request.
In your case Anders, you still need to add the old control to your page in the init method along with the new control that you now want to add. Keep a reference to this old control that you have just added in a class level variable. So something like
Control _oldControl = null;
protected void Init_Page(object sender, EventArgs e)
{
//Code to decide which wuc to load.
UserControl wucc = (UserControl)Page.LoadControl(sFilePath);
ParentControl.ContentTemplateContainer.Controls.Add(wucc);
_oldControl = wucc as Control;
//Now add the new control here.
}
//override the LoadViewState method and remove the control from the control's collection once you page's viewstate has been loaded
protected override void LoadViewState(object savedState)
{
base.LoadViewState(savedState);
ParentControl.ContentTemplateContainer.Controls.Remove(_oldControl);
}
Hope this helps. If it did, please check the checkbox next to this answer to accept it and vote it up if you like :)
In order to avoid ViewState related errors please make absolutely sure that in Page_Init you create the same control tree that was created the previous time ViewState was saved i.e. the previous postback. Simple page life cycle:
Page Init - create the control tree
- View State is loaded and applied here
Page Load - already loaded view state, you can do modifications to the control tree here
- Save View State
Page PreRender
For what it’s worth I recently had the same problem.
My scenario was as follows.
A fixed panel of filters (dropdown lists and textboxes) which built a search SQL string. On submission of the search consequent results were displayed in an editable gridview beneath.
On editing the gridview I cold effectively change the state of a database record thus removing it from the gridview under the filters previously chosen. In some cases this resulted in no results being returned thus causing me to hide the gridview.
I then found that if I used the new state of the record in the filter and resubmitted the search that error sometimes occurred.
The problem I eventually found had nothing to do with enabled viewstates etc but simply that the empty gridview, though no longer visible (changed programmatically), had not been rebound to a null datasource.
This appeared to cause the conflict and the error.
So it appears as though in my case the viewstate issue arose from a non-visible gridview that contained non-refreshed data.

What does AutoEventWireUp page property mean?

I don't understand what the AutoEventWireUp page property is responsible for.
I've read through this article, but even that I don't understand.
When a Page is requested, it raises various events which are considered to be part of it's lifecycle. I keep the visual representation created by Peter Bromberg handy with me.
The AutoEventWireUp property when True, automatically wires up some of these built-in events in the Page life cycle to their handlers. This means that you do not need to explicitly attach these events (using the Handles keyword, for instance, in VB).
Examples of these built-in events would be Page_Init and Page_Load.
If you set AutoEventWireUp to True and provide explicit wiring up of the EventHandlers, you will find them being executed twice! This is one reason why Visual Studio keeps this attribute set to false by default.
Edit: (after Chester89's comment)
It is useful to note that the default value of the AutoEventWireUp attribute of the Page is true, while the default value of the AutoEventWireUp property of the Page class is false
To add to previous answers; the automatic hooks are applied from TemplateControl.HookUpAutomaticHandlers. This method calls into TemplateControl.GetDelegateInformationWithNoAssert which contains which methods are considered as event handlers.
These are, in System.Web, version 2.0:
On all classes deriving from Page: Page_PreInit, Page_PreLoad, Page_LoadComplete, Page_PreRenderComplete, Page_InitComplete, Page_SaveStateComplete.
On all classes deriving from TemplateControl: Page_Init, Page_Load, Page_DataBind, Page_PreRender, Page_UnLoad, Page_Error.`
Transaction support for all classes deriving from TemplateControl:
Page_AbortTransaction, or if it does not exist, OnTransactionAbort
Page_CommitTransaction, or if it does not exist, OnTransactionCommit
System.Web, version 4.0, introduced a Page_PreRenderCompleteAsync for all classes derived from Page. That method, if present, will be registered using Page.RegisterAsyncTask and executed automatically "just before the PreRenderComplete event" (source: Page.ExecuteRegisteredAsyncTasks). This method seems very undocumented which suggest that it would be prefered to just call Page.RegisterAsyncTask with your own method instead.
As mentioned in the article, if you have AutoEventWireUp turned on, asp.net will automatically recognize you have a method with the page_load syntax and call it automatically:
private void Page_Load(object sender, System.EventArgs e)
{
}
This gives you a cleaner code behind at the expense of some (very) small overhead. Notice that if you don't specify it you must explicitly tell asp.net you want to handle the page load event:
this.Load += new System.EventHandler(this.Page_Load);
Note that this applies to other events in the page, as it uses a naming convention as Page_Event.

When extending a asp.net web control, at which event should additional web controls be injected?

I'm trying to avoid a composite control or using and ASCX by extending an existing control. However, I'm having trouble with getting the controls added to the inherited control and keep their view-state/post-back integrity. Whenever I add the controls during pre-render, the controls show up, but the post-back throws a viewstate exception. I tried adding them both there and during LoadViewState (which of course was a long-shot silly). Init is not available from the control which I'm extending.
The exception is
Sys.WebForms.PageRequestManagerServerErrorException:
Failed to load viewsstate. The control
tree into which viewstate is being
loaded must match the control tree
that was used to save viewstate during
the previous request. For example,
when adding controls dynamically, the
controls added during a post-back must
match the type and position of the
controls added during the initial
request
Actually, microsoft says you should override the CreateChildControls method.
You can call the base class method before or after you add the controls, I'm not sure if there is a convention there.
protected override void CreateChildControls(){
Controls.Add(someControl);
base.CreateChildControls();
}
Hope that helps!
You should add them in OnInit or in CreateChildControls. Anyway, to avoid having troubles with ViewState, read this GREAT article. Possibly, sample "4. Initializing child controls programmatically" is your case.

ASP.net ViewState - Even when disabled, some viewstate exist. Why?

Even when on the page, the EnableViewState property is disabled, I am still seeing some viewstate existing on the page:
"<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="VkBAB3n5LZYtY+nTzk1vEu1P/6QLf4qzFIKzpFRJe3DMf8UseUA/1RsO409HJX4QhkROSP0umoJvatjK/q+jXA==" />"
My question is why?
It's the control state.
If you really want to get rid of viewstate and controlstate you can use this code in the code-behind for the page, or in any class that the code-behind derives from
class MyPage : Page {
private class DummyPageStatePersister : PageStatePersister {
public DummyPageStatePersister(Page p) : base(p) {}
public override void Load() {}
public override void Save() {}
}
private DummyPageStatePersister _PageStatePersister;
protected override PageStatePersister PageStatePersister {
get {
if (_PageStatePersister == null)
_PageStatePersister = new DummyPageStatePersister(this);
return _PageStatePersister;
}
}
// other stuff comes here
}
Be very careful when doing this, though, since you're violating the contract with the controls. MSDN explicitly states that control state is always available. In practice, however, it has worked for me.
Edit:
Since I was downvoted, I like to point out again: Don't do this unless you know exactly what you are doing. In my case, almost the entire application was written in client-side javascript, and on those few occations where postbacks occurred, I always used the Request.Form collection to retrieve the values. Do not use server-side controls for anything but simple rendering if you do this.
This could be controls that are using ControlState. Any control that has control state will ignore your ViewState settings.
This article is a little old but to my understanding most of the points are still valid:
You must have a server-side form tag () 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 tag.
http://msdn.microsoft.com/en-us/library/ms972427.aspx
This is an absolutely fantastic article on ViewState if you develop in ASP.NET read it!
ASP.NET ViewState Helper is also a nice tool for seeing what's going on in your ViewState
Controlstate can be the causes. Control state can not be disabled. In ASP.NET 2.0 there is a distinction between data necessary to make a control work (controlstate), and other data (viewstate)
And yes some of the controls don't work without controlstate.
If you want to know which one is causing it or what the viewstate contains check out a viewstate viewer
The Controls which implements IPostBackEventHandler like Textbox, Checkbox, etc. will retain the state even after disabling the viewstate. The reason is during the Load Postback Data stage, these controls will get state information from Posted back form.
But controls like label which do not implement IPostBackEventHandler will not get any state information from posted back data and hence depend entirely on viewstate to maintain the state.

Resources