[Download Source Code]
The best way for demonstrating where Scott's code will fail is in a practical example. For the complete source code for the practical example in which I will demonstrate the downfall can be downloaded with the attached source code. The specific file that demonstrates the downfall is conventionally called "ScottsProblem.aspx"
Scott already explained his code in his article in immense detail; hence, I will not regurgitate what he has already written. However, I will explain the code that allows the exception to be thrown. The first code listing to step up to the plate follows (without Scott's code but it is included in the example):
public class ScottsProblem : PersistViewStateToFileSystem {
protected System.Web.UI.WebControls.PlaceHolder ControlHolder;</font>
<font face="Verdana" size="2"> protected override void OnLoad(EventArgs e) {
if (Request.QueryString["Control"] != null) {
ControlHolder.Controls.Add(LoadControl(String.Format(
"UserControl{0}.ascx", Request.QueryString["Control"])));
}</font>
<font face="Verdana" size="2"> base.OnLoad(e);
}
}
That code listing is the code behind for the ScottsProblem page. The ASP.NET page code looks like so (I left out the common code pieces):
<form id="Form1" method="post" runat="server">
<div>
<a href="ScottsProblem.aspx?control=A">Show User Control A</a><br/>
<a href="ScottsProblem.aspx?control=B">Show User Control B</a>
</div>
<asp:PlaceHolder id="ControlHolder" runat="server"></asp:PlaceHolder>
</form>
You have guessed it correctly! The above code is a simple demonstration of two user controls being dynamically added to the page based on the query string. That query string variable name is 'Control'. Essentially, the two hyperlinks are there only to facilitate the testing purposes.
There is also one thing that I would like to add: the two user controls are named UserControlA.ascx and UserControlB.ascx respectively. The only thing that they have in common is that their control tree has similar naming. For example, the ID's of the controls inside both user controls looks like the following:
|- Ctl1
|- Ctl2
Because view state saves the data according to the ID of the controls and not by it's control type (ie. DataGrid or TextBox), ASP.NET will throw an exception when it detects that the control structure is completely different between the two post backs.
With that said, time for the exact reproduction of the ASP.NET exception being thrown with Scott's code.
- Open a new browser window and browse to (assuming that you downloaded my source code and made a virtual directory named "ViewStateToFS" to the root of the source code):
http://localhost/ViewStateToFS/ScottsProblem.aspx
- From there, instruct the browser to open UserControlB in a new window. Please note that this is an essential step because:
a) We are replicating a casual user's browsing habits.
b) Opening a new instance of a browser to show UserControlB will result in the two "browser windows" taking on two different session ID's.
- On the first browser window, make the browser browse to the page that will output UserControlA.
- And the part that I enjoy (because I have a thing with atomic weapons going off), click the post back button on second windows (the one displaying UserControlB). And then you will find that you are going face to face to with the exception which I said ASP.NET will raise.
Stay tuned because on the next page, I will explain why the exception is being thrown.