A Case of Invalid ViewState

5 minute read

Last week I was helping a colleague of mine with a ViewState case that turned out to be pretty interesting…

Scenario

The customer was getting events similar to the following in the event log and needed to know why they occurred

Event Type: Information
Event Source: ASP.NET 2.0.50727.0
Event Category: Web Event
Event ID: 1316
Date: 2007-06-11
Time: 09:48:02
User: N/A
Computer: MYMACHINE

Description:

Event code: 4009
Event message: Viewstate verification failed. Reason: The viewstate supplied failed integrity check.
Event time: 2007-06-11 09:48:02
Event time (UTC): 2007-06-11 07:48:02
Event ID: 14cc57c05e834de98c7df506a013a706
Event sequence: 10
Event occurrence: 1
Event detail code: 50203

Application information:

Application domain: /LM/w3svc/1/root/MyApp-3-128260216693527710
Trust level: Full
Application Virtual Path: /MyApp
Application Path: c:\inetpub\wwwroot\MyApp\
Machine name: MYMACHINE

Process information:

Process ID: 3640
Process name: w3wp.exe
Account name: NT AUTHORITY\NETWORK SERVICE
Request information:
Request URL: http://mymachine/MyApp/MyWebForm.aspx
Request path: /TestBadViewstate/WebForm1.aspx
User host address: 127.0.0.1
User:
Is authenticated: False
Authentication Type:
Thread account name: NT AUTHORITY\NETWORK SERVICE

ViewStateException information:

Exception message: Invalid viewstate.
Client IP: 127.0.0.1
Port: 14644
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.2; WOW64; .NET CLR 2.0.50727; .NET CLR 1.1.4322; .NET CLR 3.0.04324.17; InfoPath.2)
PersistedState:
dDwxOTM2NzUxODMzO3Q8O2w8aTwxPjs+O2w8dDw7bDxpPDE+Oz47bDx0PHA8bDxfX0hlYWRpbmc7PjtsPENvdXJzZSBTZWFyY2g7Pj47bDxpPDE+Oz47bDx0PDtsPGk8MT47aTwzPjs+O2w...
Referer: http://SomeThirdPartySite.com/SomePage.htm
Path: /MyApp/MyWebForm.aspx

Custom event details:

For more information, see Help and Support Center at http://go.microsoft.com/fwlink/events.asp.

And the call stack reported was:

[HttpException (0x80004005): Validation of viewstate MAC failed. If this application is hosted by a Web Farm or cluster, ensure that <machineKey>
configuration specifies the same validationKey and validation algorithm. AutoGenerate cannot be used in a cluster.]

System.Web.UI.ViewStateException.ThrowError(Exception inner, String persistedState, String errorPageMessage, Boolean macValidationError) +119
System.Web.UI.ObjectStateFormatter.Deserialize(String inputString) +252
System.Web.UI.ObjectStateFormatter.System.Web.UI.IStateFormatter.Deserialize(String serializedState) +5
System.Web.UI.Util.DeserializeWithAssert(IStateFormatter formatter, String serializedState) +37
System.Web.UI.HiddenFieldPageStatePersister.Load() +222
System.Web.UI.Page.LoadPageStateFromPersistenceMedium() +80
System.Web.UI.Page.LoadAllState() +35
System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +9041
System.Web.UI.Page.ProcessRequest(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +217
System.Web.UI.Page.ProcessRequest() +85
System.Web.UI.Page.ProcessRequestWithNoAssert(HttpContext context) +20
System.Web.UI.Page.ProcessRequest(HttpContext context) +110
ASP.MyPage_aspx.ProcessRequest(HttpContext context) +30
System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +405
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +65

Troubleshooting

If you get view state errors on 1.1. and don’t get events like the above, make sure that you have SP1 installed or at least a version of 1.1 later than this hotfix since this hotfix introduced the type of logging above, which is crucial to troubleshooting most view state errors.

View state, as most of you know, is a Base64 encoded string containing information about the state of the controls on the web form. To avoid tampering the view state is validated against the machine key, page name etc. and if the string is either corrupt in some way such that it cant be Base64 decoded or such that it doesn’t pass validation you will get an error like the above.

Typically view state errors will occur if

  • You’re on a web farm and the machine keys are not consistent on all nodes
  • You’re on a web farm and the page is slightly different on one node than ot the others, for example if one node is upgraded to 2.0 and the other is still 1.1 or if some controls used on the page are built differently For a more comprehensive list see this KB article

In this particular case they had just upgraded to 2.0 from 1.1, they were not running on a web farm. The error occurred intermittently and only on two specific pages, but most of the time these pages were served just fine without view state errors.

Since it is very unusual for errors like this to occur in a non-web farm scenario, especially intermittently, this issue was very curious. I have seen that happen sometimes when the client was a mobile device and the view state was very large as some mobile devices will only send x kb of data so the issue there would be that the view state was corrupted because not all the view state was sent. In this case the client was IE 7.0 so no such luck…

I used Fritz Onion’s viewstatedecoder to decode the view state to verify that it wasn’t corrupted and sure enough the view state was just fine, the contents seemed to be fairly standard text boxes etc.

Lucky break

Lucky for me, and for them :) I have seen enough encoded view state to know what view state is supposed to look like, so when i took another look at the event log entry i noticed that the persisted state started with dDw… to most people this probably just looks like mumbo jumbo but I happen to know that view state on 2.0 is supposed to start with /wE… in fact when I browsed their site on the internet I could indeed see that the typical view state for these affected pages (from the hidden view state field in view source) was perfectly normal 2.0 view state while the dDw… that was sent to the page is typical for 1.1 view state.

Knowing this, the question is now, where does this 1.1. view state come from?This is where the event log entry comes in handy again… and if you have jumped ahead a bit you have probably noticed by now that the referrer is a htm page http://somethirdpartysite.com/SomePage.htm, in other words. there is nothing wrong with the site itself, the problem is that somehow this 3rd party site is posting 1.1. view state to the page, and of course that won’t validate well against the new 2.0 page.

Browsing to the 3rd party site and looking at the source for the htm file we can see what we already suspected… the page contains a form, with a hidden view state field and the post action for the form is our aspx page, so this 3rd party site apparently did a bit of a hack, copying the view state while this site was still 1.1. and posting that view state to the form…

Technically, no-one but the aspx page itself should really be allowed to post to the aspx page, so anytime the referrer of a post to the aspx page is someone other than itself that is bad, and again, to guard against things like this the view state validation exists, but of course it might prove to cause a bit of a troubleshooting headache for you.

Conclusion

The solution in this case was to talk to the 3rd party site, let them know about the upgrade and ask them to avoid posting to the site but rather link to the site or redirect to it since there is no way of knowing how long view state will be valid as it can change with any type of upgrade to the page.

If there is a benefit to having the 3rd party site being able to post data and show the results in their proprietary format, a web service would be a pretty good solution.

Until next time, Tess