(In which a problem with ViewState is solved by tweaking Visual Studio’s debugging options and using ViewState Decoder to locate the problem on the page)
When an error occurs in your code as you run it through the Visual Studio Debugger, you’ll know all too well that Visual Studio is given focus, opens the code file where the error has occurred and highlights the line it has occurred on. Recently, I came across the problem where as soon as I caused a page to postback, a ViewState error was instantly thrown before any of my code had run.
Now typically if you see this error, you start searching your code for the phrase ‘Controls.Add’ because the error implies that you have changed the structure of the page after the state of the page has been saved into the StateBag. Statements like Page.Controls.Add(…) are the usual culprits as this is exactly what they do. However, there were no such statements in my entire site, let alone this particular page.
To discover the exact problem then, I told the debugger to show me every error that occurred, not just the ones in my code as follows
- In Visual Studio, select Tools > Options > Debugging > General
- Uncheck “Enable Just My Code (Managed only)” and hit OK.
- Press Ctrl + Alt + E to bring up the Exceptions dialog. This allows you to specify which errors the debugger should break to code on encountering. Check ‘Common Language Runtime Exceptions’ to break on any .NET Exception. Drill down into the tree to be more specific – e.g. to break only those Exceptions in the System namespace. Hit OK.
Debugging into the page again, the debugger quickly identified a System.InvalidCastException occurring with the message
After clicking continue, the ‘Failed To Load Viewstate Error’ then appeared and we were back to the error we’d seen before. All the InvalidCastException message tells us is that as the server loaded the viewstate from the page back into the pipeline for processing, it expected an ArrayList and got a String array instead. By inspecting the page’s viewstate then, we could investigate where this clash might be occurring and try to map it to the page.
Enter Fritz Onion’s ViewState Decoder app, a really handy download which takes that encoded hidden field on your page and renders it into something more legible. Loading my erroring page into the decoder presented me with the following.
As luck would have, it turned out there was only one string array in the entire viewstate tree (highlighted above) and that highlighted this line in the markup was the likely cause
src="<%# ResolveUrl("~/scripts/swfobject.js") %>">
Sure enough, commenting out the call to DataBind() stopped the ViewState error occuring on the page, but the location of the script in the header was not resolved. Rather than using an absolute URL, I ended up opting for a Literal control which generated the correct script tag instead and all was well.