Viewstate error in mobile ASP.NET app
This is my third mobile post this week! This one was tricky to track down so hopefully this will save someone some time. The symptom you see is that users get the following exception. If you're using ASP.NET 2.0, we would log this to the Event Viewer by default thanks to Web Events:
Exception of type 'System.Web.HttpUnhandledException' was thrown. ---> System.Exception: The page requires session state that is no longer available. Either the session has expired, the client did not send a valid session cookie, or the session state history size is too small. Try increasing the history size or session expiry limit. |
This error would appear randomly throughout the day in a high throughput site. We were able to track this down using the IIS logs, Network Monitor, and in this case, the exceptions logged in the Event Viewer. The event logging in 2.0 captures a lot of information that is useful for lining up the exception with data gathered. In this instance, we used the client IP linked to the request and then filtered the Network Monitor logs using this IP. This allowed me to track the user's requests to see how they were using the site at the time of the failure.
In this case, we could see the client making requests for a few minutes, then their traffic would go away for longer than the session timeout. Their next request would come in for a page that they weren't browsing prior and would cause the exception. Looking at this data, we determined that users were bookmarking the site on their mobile devices. While this normally isn't a big deal, there are some devices that result in an __viewstate field in the QueryString. When you bookmark this URL, the initial request is now going to cause the mobile page to lookup the viewstate which is stored in Session for mobile forms. Since this is the first request, the session is just now being initialized, the ViewState isn't available, and the exception is thrown.
You can avoid this problem by adding the following code to Session_Start in the global.asax or a HttpModule. You can even get fancier and add some code to only remove the __viewstate QueryString if your pages are looking for other items in the QueryString collection. This code will ensure that when a new session is being created, that the __viewstate QueryString is not part of that request.
void Session_Start(object sender, EventArgs e) { // Code that runs when a new session is started if (HttpContext.Current.Request.QueryString.Count > 0) HttpContext.Current.Response.Redirect(HttpContext.Current.Request.Url.LocalPath.ToString()); } |
You could also track this down by logging the QueryString in the IIS logs and looking for __viewstate in that field. The exception logged in the Event Viewer in 2.0 also log the UTC time to make it easy to line up the IIS entries which use UTC by default with the exception.