My latest set of Working with Data in ASP.NET 2.0 tutorials focused on paging and sorting data and included a look at implementing custom paging (with sorting) with the GridView and ObjectDataSource. Alert reader Mark Fox pointed out that there's a bit of a problem when using custom paging and clicking the Last page link in the paging interface:
For lesson 25 – Efficient Paging I downloaded the file ASPNET_Data_Tutorial_25_VB.exe and than opened the project in VS 2005 Standard and ran PagingAndSorting/EfficientPaging.aspx. Clicking the PageLast >> button in GridView1’s pager gives a System.OverflowException in System.Web.UI.WebControls.GridView.CreateDataSourceSelectArguments().
Enabling the viewstate in GridView1 fixes this.
With custom paging, the page count value returned by the ObjectDataSource’s SelectCountMethod is stored in the GridView’s view state. Other GridView variables – the PageIndex, EditIndex, SelectedIndex, DataKeys collection, and so on – are stored in control state, which is persisted regardless of the value of the GridView’s EnableViewState property. Since the PageCount value is persisted across postbacks using view state, when using a paging interface that includes a link to take you to the last page, it is imperative that the GridView’s view state be enabled. (If your paging interface does not include a direct link to the last page, then you may disable view state.)
Clicking the last page link causes a postback and instructs the GridView to update its PageIndex property. If the last page link is clicked, the GridView assigns its PageIndex property to a value one less than its PageCount property. With view state disabled, the PageCount value is lost across postbacks and the PageIndex is assigned the maximum integer value instead. Next, the GridView attempts to determine the starting row index by multiplying the PageSize and PageCount properties. This results in an OverflowException since the product exceeds the maximum allowed integer size.
To see the problem in code, use Reflector and drill into the GridView's HandleEvent method. There you'll find a switch statement that handles the different types of events, one of them being when the last page link is clicked:
num1 = this.PageCount - 1;
num1 = 0x7fffffff;
So if view state has been disabled, then num1 (the page the GridView is going to try to access) is set to the maximum integer value (2.147 billion, roughly). Next, look in the GridView's CreateDataSourceSelectArguments() method, and there you'll find:
arguments1.StartRowIndex = this.PageSize * this.PageIndex;
That multiplication right there is what causes the OverflowException, as any PageSize value greater than 1 will result in a value that exceeds the largest possible integer value.
The fix? Enable view state in your GridView so that the PageCount property can be remembered across postbacks.