We have a fairly complex form in our ASP.Net 2.0 app. It has a few buttons on it that load various modal selection windows for different data items.
Bug raised: Fill in all the data, including using these three popup windows, hit save, and the Drop Downs on the screen clear out.
Debugging:
We worked out pretty early that those dropdowns were losing their ViewState.
Clicking any 3 combinations of the buttons is enough to repro the bug (ie 1 button 3 times), any 2 buttons is fine, as is one button twice.
Closing the selection windows rather than selecting something worked fine, so we started suspecting some sort of dynamic data updating issue, a la EventValidation.
Because we use the SessionStatePersister, some deep gut instinct made me disable this back to the default HiddenFieldPageStatePersister, at which point everything started working correctly.... hmmm....
So we know it's related to ViewState, but why this magical threshold of 3 Clicks??
Brilliant co-worker #1 wasn't happy with my (totally pragmatic) workaround of just setting that one page to use the HiddenFieldPersister, so he dug deeper.
Using Reflector, a little bit of code caught his eye:
if (
(sessionPageState != null && count > sessionPageState.HistorySize)
||
(sessionPageState == null && count > 9)
) {
string name = (string) queue.Dequeue();
session.Remove(name);
}
In other words, because the data stored by the SessionPersister is survives past the use of each page, it stores the data in a queue, and clears the old data as it fills up (as Rico said - "A cache with a bad clearance policy is another name for a memory leak").
As the code snippet above implies, the default queue length is 9.
So with our page:
1. Main Page Load
2. Popup #1 Load
3. Popup #1 Postback
4. Popup#1 Select
5. Popup #2 Load
6. Popup #2 Postback
7. Popup#2 Select
8. Popup #3 Load
9. Popup #3 Postback
10. Popup#3 Select
11. Main Page Postback
The observant will notice that 11 > 9, and so our main page's viewstate wasn't available in session when it needed it!!
Turns out it's easy to fix too, just add:
to the system.web section of your config file.
<sessionpagestate historysize="number">
It added a few grey hairs though!
3 comments:
It sounds like you attached set the SessionStatePersister to be used for all your pages, instead of your main page. This means your Popups are occupying the viewState queue.
My solution was to only attach the SessionStatePersister (using a PageAdapter) to my Main page class and not to System...Page class. This prevented my popups from every messing with the Main page's ViewState. This means that the popups then use the default HiddenFieldPageStatePersister, which is ok with me. If I want the popup pages to use a SessionStatePersister, I define it again for the popup page (separately for the main page).
Rich
Hi,
I just had the same issue you describe :) Thank you for this post.
If you dont require sessionstatepagepersister probably is better that you leave it on the HiddenfieldStatePagepersister.
You could also override PageStatePersiters on the page and write your own Persister ...
Post a Comment