Is ViewState totally incompatible with Fragment OutputCache? - asp.net

I have a custom control in a page which uses full and partial output caching. If I simply refresh the page, the control is loaded from cache (I've added a timestamp to verify that). But if I do an action in the control that causes PostBack, the second time I do it the ViewState "loses" a value that was added in Page_Load when !IsPostBack. I wonder if there is some way to have both ViewState and OutputCache working in this way.
public partial class MyUserControl : MyBaseUserControl
{
private string MyProperty
{
get { return (string)ViewState["_myProperty"]; }
set { ViewState["_myProperty"] = value; }
}
protected override void LoadViewState(object savedState)
{
base.LoadViewState(savedState);
var prop = this.MyProperty;
}
protected void Page_Load(object sender, EventArgs e)
{
// Do something
if (IsPostBack)
{
var value = this.MyProperty; // sometimes gets null
}
else
{
this.MyProperty = GetNewValue(); // never returns empty or null
}
}
}
Edit: After posting the question, SO showed other related questions (like this), so I've reviewed Page Life Cycle and overriden LoadViewState method, and set breakpoints. When page (and control) is first loaded, Page_Load is called, but LoadViewState not; in first PostBack, LoadViewState is called and MyProperty has the correct content; in second PostBack, again Page_Load is called, but LoadViewState not, and MyProperty has null value.
Edit 2: I've debugged a little more (by comparing execution with Output Cache disabled) and found out that control postbacks (an asp:GridView's OnSelectedIndexChanging event) force the page to refresh by injecting a window.location=window.location; JavaScript in the page. But with cache enabled, gridview's event is executed only in the first postback, but not in the second one, preventing the page (and, subsequently, the control) to be reloaded to complete its task. But it's not the only problem, because of the property stored in ViewState.

Related

ViewState not reatining value on postback / In which stage of page lifecycle is viewstate to be used

I apologize in advance if the Title seems absurd. I am trying to understand the answer to both in a situation I am stuck in. I am creating user controls dynamically on a button click while keeping track of the count in viewstate. Following is the code:
private int custControlCountID;
public int CustControlCountID
{
get
{
return (int)(ViewState["CustControlCountID"] == null? 1 : ViewState["CustControlCountID"]);
}
set
{
ViewState["CustControlCountID"] = value;
}
}
protected void Page_Init(object sender, EventArgs e)
{
for (int i = 0; i < CustControlCountID; i++)
{
RejRow customControl = (RejRow )LoadControl("~/RejRow .ascx");
customControl.ID = "rejRow" + i;
divHolder.Controls.Add(customControl);
}
}
protected void btnNewRow_Click(object sender, EventArgs e)
{
CustControlCountID = CustControlCountID + 1;
RejRow customControl = (RejRow)LoadControl("~/RejRow.ascx");
customControl.ID = "rejectRow" + CustControlCountID;
divHolder.Controls.Add(customControl);
}
I have shared only relevant code. On clicking the button control is added successfully but only once. This is because CustControlCountID is always set to 1 on Page_Init.
I have learnt that LoadViewState is called after Page_Init hence the value I am setting is not available in Page_Init. I have also learnt that controls to be added in Page_Init during which control hierarchy is built. Please help me understand this.
A theory suggests that as the ViewState is loaded between Page_init and Page_load, the value you get during Page_init is not from a loaded viewstate, and if you set it, it is probably going to be overridden when the framework actually loads it in the following step on the page life cycle.
You could try loading your controls initially by overriding the CreateChildControls method.

.NET Public Events not wiring up in nested web user controls

I have C# Web Application that has an aspx page hosting a user control (Review.ascx). Inside that user control there are 5 more user controls, one of which has a public event (Review_Summary.ascx). The problem is no matter what i do I cannot get the event wired up in the parent ascx control (Review.ascx).
Here is what I have in the child control (Review_Summary.ascx)
public event EventHandler forwardStatusChanged;
#region methods
protected void btnForward_Click(object sender, EventArgs e)
{
if (btnForward.Text == "Return")
{
if (forwardStatusChanged != null)
{
forwardStatusChanged(sender, e);
}
removeForward();
}
}
In the parent control (Review.ascx) I have this
public void initReview(string EmployeeNumber)
{
RevSummary.forwardStatusChanged += new EventHandler(RevSummary_forwardStatusChanged);
<more code here>
}
protected void RevSummary_forwardStatusChanged(object sender, EventArgs e)
{
lblReadOnly.Visible = false;
}
RevSummary is the ID of the child control in the parent control. InitReveiw is a method that is called by the aspx page in its Page_Load event.
I get no errors on compile or at runtime. But when I click the button the forwardStatusChanged event is null. The "removeForward()" method that is called after that executes properly. So that fact that the event is always null leads me to believe that the wire up in the parent control is not working. However, I am sure it is executing becasue all of the code after that executes.
How can I figure out why this event is not wiring up?
Where is initReview being called from? Are you sure it's being called because the only reason this happens is that the event handler wasn't truly setup. I've never found a reason other than this, the several times I did this myself.
HTH.

Get state of ASP.NET page life cycle

I need the following functionality in my method: if the method is called before OnLoad event of ASP.NET life cycle throw an exception else continue execution of the method.
I was thinking of something like this:
if (Page.LifeCycleState < LifeCycleState.OnLoad) {
throw new InvalidPageStateException();
}
Is it possible to retrieve the state of ASP.NET page life cycle?
One approach would be to use a Basepage that you always use in your site. This would contain a variable called PageLoadComplete, which you would set at the end of your PageLoad event. Then you could check the state of this variable from within your method.
public abstract class BasePage : System.Web.UI.Page
{
public bool PageLoadComplete { get; private set; }
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
PageLoadComplete = true;
}
}
If you want to access the variable from code external to your page such as a UserControl, you would have to make it public and cast your page as BasePage.
public partial class MyUserControl : System.Web.UI.UserControl
{
protected void Page_Load(object sender, EventArgs e)
{
BasePage basePage = this.Page as BasePage;
if (basePage != null && !basePage.PageLoadComplete)
{
throw new InvalidPageStateException();
}
}
}
There is property in a realization of System.Web.UI.Control class(realization):
internal ControlState ControlState {
get { return _controlState; }
set { _controlState = value; }
}
Where ControlState is enum that contains members such as: Initialized, ViewStateLoaded, Loaded etc. here declaration
But as you can see this property is internal. So only way to get control state is proposed by Daniel Dyson.
You maybe able to find what you are looking for, by looking at the CurrentHandler and PreviousHandler properties of the current HttpContext.
if the method is called before OnLoad event of ASP.NET life cycle
throw an exception else continue execution of the method.
It is not clear which Onload event is meant, nor where the "method" resides. Is it the Page's Onload or a Control's OnLoad? Is it a Page's "method" or a Control's "method"?
Anyway, one can store sort of flag in the Context.Items Dictionary, which all controls (including Page) have access to during a request. This eliminates the need to use a general base page like suggested obove.
In the OnLoad method (no matter whether it is a Page's OnLoad or a Control's OnLoad):
Context.Items[UniqueID] = this;
In the "method":
if (Context.Items[UniqueID] != null)
{
throw new InvalidPageStateException();
}

User control event or method override where custom properties are valid?

I have an ASP.NET user control that is used in another use control. The parent user control uses data-binding to bind to a custom property of the child user control.
What method can I override or page event where I am ensured that the property state is set?
I think in a page it is PageLoaded versus the Page_Load override? I am looking for this in the user control because my property is always null even though it is set.
Thanks.
Example. This is in my user control. FilterEntryId is being bound from inside another user control:
protected int _filterEntry = -1;
public int FilterEntryId
{
get
{
return _filterEntry;
}
set
{
_filterEntry = value;
}
}
protected void Page_Load(dobject sender, EventArgs e)
{
FilterEntry always -1!!
}
The property is being set but never has value when Page_Load. The Page_LoadComplete may be the proper place but does not seem to be an option in user control. I've also tried Page_DataBind.
My hypothesis is that this is a page lifecycle issue but it may be something else.
Not sure what you need to do with that property but since you can't be sure when will be set. Can't you add your logic on the set of the property?
Another option would be a later event as PreRender.
public int FilterEntryId
{
get
{
return _filterEntry;
}
set
{
_filterEntry = value;
//HERE YOUR LOGIC
}
}

User Control's Viewstate

In some book I've seen that they save custom properties of user control like this:
private int id = 0;
public int ID
{
get { return id; }
set { id = value; }
}
protected void Page_Init(object sender, EventArgs e)
{
this.Page.RegisterRequiresControlState(this);
}
protected override void LoadControlState(object savedState)
{
object[] ctlState = (object[])savedState;
base.LoadControlState(ctlState[0]);
this.ID = (int)ctlState[1];
}
protected override object SaveControlState()
{
object[] ctlState = new object[2];
ctlState[0] = base.SaveControlState();
ctlState[1] = this.ID;
return ctlState;
}
My question is why can I simply store it (in setter) in viewstate like: Vistate["ID"]=id;
and then retrieve it form there?
There is a difference between ViewState (what you are talking about in your question) and ControlState (what is shown in the sample code):
ViewState can be turned off by the user of your UserControl, by setting EnableViewState="false". In that case, you wouldn't be able to restore your property's value during the next request/postback (because there is no ViewState).
ControlState cannot be turned off. This means, that whatever you store in ControlState will be available during the next postback and you should therefore use ControlState for data that you absolutely need to be able to retrieve during the next request/postback.
See also these pages in MSDN: ASP.NET ViewState Overview and ControlState vs. ViewState
Excerpt from the first page:
In addition to view state, ASP.NET
supports control state. The page uses
control state to persist control
information that must be retained
between postbacks, even if view state
is disabled for the page or for a
control. Like view state, control
state is stored in one or more hidden
fields.

Resources