Last post Nov 23, 2008 04:29 AM by danludwig
Jun 30, 2007 11:14 AM|martinhn|LINK
Why does the ViewState not work on ClientCallback?
I have an ASPX page with three UserControls hosted on it.
Each UserControl manipulates with the same Business Object – and therefore I would like to store the object in only one location – and not on each UserControl – because then I have
to update the object on each UserControl when I flick between them.
Then I thought it could be good to have a BasePage-class that derives from System.Web.UI.Page – and store the object here in the ViewState. Therefore I made two generic methods:
The first method stores the object of type T in the page’s ViewState – the second retrieves the object. Very trivial.
It works absolutely fine from each of those UserControls. I can get and set properties on the object and the values are maintained when I flick between the UserControl (Event fire
on the UserControl – and the ASPX hides and shows the correct UserControls accordingly)
But then the tricky part comes. On my second UserControl – I have another UserControl which implements the ICallbackEventHandler to provide nice AJAX functionality. I can easily
access the object from this UserControl.
But… When I set a value on a ClientCallback – something is wrong. I can set the value – but when I get the value - I get the old value.
So I can easily get the values from ClientCallback and also regular methods and eventhandlers (like when you click a button) – but when I set the values they are not there when I
want to get them from e.g. the third UserControl. Or the same UserControl it-self.
If I change the two generic methods to use Session or Cache – it all works fine. But I hate Session – I need the objects to be completely gone when I navigate away from my ASPX page,
and onto another ASPX – just like ViewState does.
Source code can be found here:
http://blog.killerclickz.com/2007/06/30/AsyncViewStateIssueInASPNET.aspx - unzip it, and take a look at it...
View state Problem
↑ Grab this Headline Animator
Jun 30, 2007 11:30 AM|joteke|LINK
I think it's because callbacks do not round-trip ViewState like normal postbacks do. It is explained quite well in
ASP.NET ajax's UpdatePanel is capable to do this, it keeps ViewState in sync with async postbacks in partial page rendering.
Jun 30, 2007 01:52 PM|martinhn|LINK
Well - the article didn't really solve my problem. My problem is the read-only obstacle pointed out in the article. My problem is - that i can get values from my object from a Callback - but the new values are not set when doing so from a callback. It hasn't
got anything to do with controls on the page - i save my own business object in the ViewState....
Jun 30, 2007 03:56 PM|joteke|LINK
It was pointed in the article to second article where he had implemented some mechanism to keep state sync between callbacks (a dictionary).
Basically, viewstate is posted to the server, along with all other forms fields, when you do a callback, but it is never taken down as part of the callback result and updated at the client. And as the viewstate originates from when page was rendered from
the server, it's that same state that gets posted and therefore no change in value is seen. Point is, callback is rendered before any predenering or viewstate saving occurs.
Public Function GetCallbackResult() As String Implements System.Web.UI.ICallbackEventHandler.GetCallbackResult
'Save state with PageStatePersister and place it to Page.ClientState
Dim mi As System.Reflection.MethodInfo = GetType(Page).GetMethod("SaveAllState", Reflection.BindingFlags.Instance Or Reflection.BindingFlags.NonPublic)
'Get serialized viuewstate from Page's ClientState
Dim stateProp As System.Reflection.PropertyInfo = GetType(Page).GetProperty("ClientState", Reflection.BindingFlags.Instance Or Reflection.BindingFlags.NonPublic)
Dim state As String = stateProp.GetValue(Me, Nothing)
Return returnValue & "|" & state
After this it's easy to update the viewstate field at client on the callback handler
document.getElementById("ResultsSpan").innerHTML = data;
What comes to not posting changed values with the callback, that's because they are gathered at WebForm_InitCallback method of the Page Framework e.g they are gathered when page loads. It's simple to overcome that too. In the callbacking to server method, just initialize the array and post data variables and call WebForm_InitCallback again yourself
__theFormPostCollection.length = 0;
//Do the callback after this
Jul 01, 2007 11:12 PM|martinhn|LINK
That solved my problem...
And the IniCallback () looks like this:
__theFormPostCollection.length = 0;
And when the callback returns to the client:
In code-behind i do this:
Now I get the correct values - after I update the ViewState hidden field manually.
Jan 16, 2008 12:31 AM|neal.xia|LINK
It works. Thanks. But in case Page.EnableEventValidation is true, the
value of hidden field __EVENTVALIDATION is broken by the new updated
VIEWSTATE. So if I click the submit button on the page, it can't pass the
event validation of the page.
Do you know how to update __EVENTVALIDATION manually?
Thanks for your time in advance,
Jan 16, 2008 03:38 PM|joteke|LINK
Page internally causes it to be created by calling internal method
Try to play with that with previous idea.
Jan 16, 2008 03:52 PM|neal.xia|LINK
Thanks for the quick response. Actually, I did it like your suggestion. Following methods are invoked in ICallBackEventHandler.GetCallBackResult.
public string GetCallbackResult()
StringBuilder sb = new StringBuilder();
private string GetUpdatedViewState()
// Save state with PageStatePersister and place it to Page.ClientState
System.Reflection.MethodInfo mi = typeof(Page).GetMethod("SaveAllState", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
// Get serialized viewstate from Page's ClientState
System.Reflection.PropertyInfo stateProp = typeof(Page).GetProperty("ClientState", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
string state = stateProp.GetValue(this.Page, null).ToString();
private string GetUpdatedEventValidationFieldValue()
System.Reflection.MethodInfo mi = typeof(ClientScriptManager).GetMethod("EnsureEventValidationFieldLoaded", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
System.Reflection.MethodInfo mi2 = typeof(ClientScriptManager).GetMethod("GetEventValidationFieldValue", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
string s = (string)mi2.Invoke(this.Page.ClientScript, null);
But I found the event validation field value is not updated by the new view state. I guess I might need to call some internal things to make it work.
Jan 16, 2008 06:28 PM|joteke|LINK
Funny is, that if yoiu're using Reflector, see Page's RenderCallback method. With quick look, it seems it should send event validation data down by default.
Jan 17, 2008 07:00 PM|neal.xia|LINK
After reading the code of PageRequestManager.RenderPageCallback() in ASP.NET AJAX, I fixed the problem. I've to say, the guy who wrote that talented code is my idol. :-)
Jul 29, 2008 04:58 PM|macruiisel|LINK
Can you point me where you got the code for PageRequestManager.RenderPageCallback() that gave you the idea to fixed this problem?
I'm trying to update the viewstate on a callback but i'm always getting the invalid state error when i enable validation.
Nov 20, 2008 11:39 PM|danludwig|LINK
I checked the source of the PageRequestManager client script file, and cannot find the RenderPageCallback method. You said you saw this in reflector -- is it compiled server code, or clientscript? If compiled server code, is it a private method of some particular
Nov 22, 2008 03:01 AM|danludwig|LINK
Using the above method to persist viewstate during a callback works. During multiple callbacks, I can always retrieve the stored ViewState from the previous callback.
However, this only works consistently when eventvalidation is disabled. When event validation is enabled, only the first callback is successful. On second and subsequent callbacks (and postbacks after the first callback), I get the "The state information
is invalid for this page and might be corrupted." exception. I can read this exception by overriding the OnInit method of my control and invoking Page.ClientScript.ValidateEvent(ControlRegisteredForEventValidationInRender.UniqueID) during callbacks and
postbacks. "ControlRegisteredForEventValidationInRender" is a reference to a control that is registered for event validation during the initial Render method, and it is a control whose state is changed on the client as the result of callbacks.
Back to the exception... it has an InnerException that says "Invalid viewstate" and includes the encoded viewstate string and http header information.
I've also discovered that the page's __EVENTVALIDTION hidden field is automatically updated after a callback. I have tried leaving it as is, replacing it with the hidden value that was originally rendered, and changing it to the result of a GetEventValidationFieldValue
method invocation as described in this post. No matter how I try to give the __EVENTVALIDATION field the correct value, it always seems to end with the same result: First callback works, and after that, state information corruption.
It seems like the viewstate and eventvalidation need to jive together, but since I'm changing the viewstate during a callback (as described above), it's not jiving with any serialized __EVENTVALIDATION values. What do I need to do to make sure the __EVENTVALIDATION
value is correct after I update and save the viewstate during a callback?????
Nov 23, 2008 04:29 AM|danludwig|LINK
I couldn't solve this event validation problem when manually updating viewstate during a callback. However, I was able to come up with an alternative that does save some state during a callback, with event validation enabled: